1.数组基本知识点
1.1概念
数组就是一个集合。数组会用一些名为索引的数字来标识每项数据在数组中的位置,且在大多数编程语言中,索引是从 0 算起的。我们可以根据数组中的索引,快速访问数组中的元素。
数组中的元素在内存中是连续存储的,且每个元素占用相同大小的内存。
1.2 相关操作的时间复杂度和空间复杂度
访问元素时间复杂度都是O(1),空间复杂度O(1),因为对于固定大小的数组,访问时间不随数组大小而变化。通过下标可直接访问。
修改元素:时间复杂度O(1),空间复杂度O(1),与n无关,通过下标可直接修改
插入元素和删除元素:时间复杂度O(1),空间复杂度O(1),插入和删除元素都需要移动后面的元素,因此随n变化。
题1:寻找数组的中心索引
给你一个整数数组 nums ,请计算数组的 中心下标 。
数组中心下标是数组的一个下标,其左侧所有元素相加的和等于右侧所有元素相加的和。
如果中心下标位于数组最左端,那么左侧数之和视为 0 ,因为在下标的左侧不存在元素。这一点对于中心下标位于数组最右端同样适用。
如果数组有多个中心下标,应该返回 最靠近左边 的那一个。如果数组不存在中心下标,返回 -1 。
解答思路:
代码案例:
class Solution
{
public:
int pivotIndex(vector<int> &nums)
{
int size = nums.size();
if (size <= 0)
{
return 0;
}
int sum = 0;
for (int &i : nums)
{
sum = sum + i; //第一步:先用for循环求总和
}
int leftsum = 0;
for (int i = 0; i < size; i++)
{
if (leftsum == (sum -leftsum - nums[i]))//第二步和第三步和第四步
{
return i; //第五步
}
leftsum += nums[i];//第五步
}
return -1;//第六步
}
};
题2:搜索插入位置
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
解题思路:
代码案例:
class Solution
{
public:
int searchInsert(vector<int> &nums, int target)
{
if (nums.size() <= 0)
{
return -1;
}
int left = 0;
int right = nums.size() - 1;
int middle = left + (right - left) / 2;
while (left < right)
{
middle = left + (right - left) / 2;
if (target == nums[middle])
{
return middle;
}
else if (target < nums[middle])
{
right = middle - 1;
}
else if (target > nums[middle])
{
left = middle + 1;
}
}
if (target >= nums[left])
{
return left + 1;
}
else if (target < nums[left])
{
return left;
}
else
{
return -1;
}
}
};
题3:合并区间
以数组 intervals 表示若干个区间的集合,其中单个区间为 intervals[i] = [starti, endi] 。请你合并所有重叠的区间,并返回 一个不重叠的区间数组,该数组需恰好覆盖输入中的所有区间 。
解题思路:
代码案例:
class Solution
{
public:
vector<vector<int>> merge(vector<vector<int>> &intervals)
{
if (intervals.size() == 1)
{
return intervals;
}
sort(intervals.begin(), intervals.end()); // 第一步:排序,确保第一个start小于第二个start
vector<vector<int>> returnvector;
returnvector.push_back(intervals[0]);//第二步:先放入第一个值,以此为判断
int j = 0;
for (int i = 1; i < intervals.size(); i++)
{
if (returnvector[j][1] >= intervals[i][0])//第三步:如果第一个值的end大于第二个值的start,则合并
{
returnvector[j][1] = max(returnvector[j][1], intervals[i][1]);//选择第一个值的end和第二个值end中最大的那个
}
else //否则,说明没有公共区间,则放入第二个
{
returnvector.push_back(intervals[i]);//只有合并完成,才会往后判断,否则一直基于此子数组进行合并
j++;
}
}
return returnvector;
}
};
题4:旋转矩阵
给你一幅由 N × N 矩阵表示的图像,其中每个像素的大小为 4 字节。请你设计一种算法,将图像旋转 90 度。
不占用额外内存空间能否做到?
代码案例:
class Solution
{
public:
void rotate(vector<vector<int>> &matrix)
{
int N = matrix.size();
// 第一步:先对角线反转
for (int i = 0; i < N; i++)
{
for (int j = i; j < N; j++)
{
swap(matrix[i][j], matrix[j][i]);
}
}
// 第二步:水平翻转
for (int i = 0; i < N; i++)
{
for (int j = 0; j < N / 2; j++)
{
swap(matrix[i][j], matrix[i][N - 1 - j]);
}
}
}
};
题5:零矩阵
编写一种算法,若M × N矩阵中某个元素为0,则将其所在的行与列清零。
思路:
代码案例:
class Solution
{
public:
void setZeroes(vector<vector<int>> &matrix)
{
int M = matrix.size();
int N = matrix[0].size();
vector<int> x;
vector<int> y;
for (int i = 0; i < M; i++)
{
for (int j = 0; j < N; j++)
{
if (matrix[i][j] == 0)
{
x.push_back(i);
y.push_back(j);
}
}
}
for (auto &i : x)
{
for (int j = 0; j < N; j++)
{
matrix[i][j] = 0;
}
}
for (auto &i : y)
{
for (int row = 0; row < M; row++)
{
matrix[row][i] = 0;
}
}
}
};