一、预备知识
概念
数组是存放在连续内存空间上的相同类型数据的集合。
特性
数组下标都是从0开始的;
数组内存空间的地址是连续的;
数组的元素不能删除,只能覆盖;
因为数组的在内存空间的地址是连续的,所以我们在删除或者增添元素的时候,就难免要移动其他元素的地址。
如果使用C++的话,要注意vector 和 array的区别,vector的底层实现是array,严格来讲vector是容器,不是数组。
注意:C++中二维数组是连续分布的,而Java中是不连续分布的。
二、二分查找
题目描述
题解
1)法一:(时:o(logn),空:o(1))
注意循环不变量原则:在while寻找中每一次边界的处理都要坚持根据区间的定义来操作。
注意的知识点
1)left + (right - left) / 2防溢出;
2)vector容器:只有C++11以上才可利用列表初始化;.size()可以获取容器大小;
三、移除元素
题目描述
题解
1)法一:暴力解法(时:o(n^2),空:o(1))
双层for循环,一个for循环遍历查找要删除的数组元素 ,第二个for循环更新数组。
2)法二:双指针法(时:o(n),空:o(1))
快指针用于查找新的数组元素(即无需删除的元素),慢指针指向要删除的数组元素。
注意的知识点
1)数组的元素在内存地址中是连续的,不能单独删除数组中的某个元素,只能覆盖;
四、有序数组的平方
题目描述
题解
1)法一:暴力解法(时:O(n+nlogn),空:O(1))
每个元素平方后进行排序。
2)法二:双指针法(时:O(n),空:o(1))
数组本来有序, 只不过负数平方之后可能影响次序,故数组平方的最大值就在数组的两端,不是最左边就是最右边。
注意的知识点
1)vector向量,可理解为“变长数组”(即“长度根据需要而自动改变的数组);
2)iterator迭代器,可理解为一种类似指针的东西,可以通过 *it 来访问vector里的元素;
3).begin()函数: 取首元素地址;.end()函数:取尾元素地址的下一个地址,作为迭代器末尾标志,不存储任何元素;
4)vector<int> a(n, 0)创建大小为n且元素初始值为0的容器;
五、长度最小的子数组
题目描述
题解
1)法一:暴力解法(时:O(n^2),空:o(1))
两层for循环依次遍历寻找合适的子序列。
2)法二:滑动窗口(时:o(n),空:o(1))
根据当前子序列和大小的情况,不断调节子序列的起始位置。当前窗口的值>=target时,窗口就要向前移动(即向后调整窗口的起始位置);窗口的结束位置为遍历数组的指针,也就是for循环里的索引。
注:时间复杂度看每一个元素被操作的次数。每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。
3)法三:前缀和+二分法(时:o(nlogn),空:o(1))
新建一个数组sums用于存储前i个元素的和,可以将寻找target的子序列转换为寻找和为sums[i]-target的前缀和,利用二分法在sums中寻找满足<=该前缀和的下标(即子序列起始位置的前一位)。
注意的知识点
1)INT32_MAX可表示初试最大值;
2)滑动窗口思想:根据当前子序列和大小的情况,不断调节子序列的起始位置;
3)求解连续子数组的常用思路:滑动窗口;前缀和;
六、螺旋矩阵II
题目描述
题解
1)法一:模拟法(时:o(n^2),空:o(1))
模拟矩阵的生成。
注意的知识点
1)二维数组容器的定义:vector<vector<int>> mat;
2)二维数组迭代器的遍历;