文章目录
前言
代码随想录day1——数组
一、数组
(1)注意vector 和 array的区别,vector的底层实现是array,严格来讲vector是容器,不是数组。
(2)数组元素只能覆盖不能删除
(3)数组下标从0开始,数组内存空间地址是连续的,删除或添加元素时,就会移动其他元素的地址
1.1 二分查找(3.9)(3.25)
1.1.1 特点
数组中无重复数组+有序数组
1.1.2 重点
两种区间定义:
a、左闭右闭
while(left<=right)
if(nums[middle]>target) right=middle-1;
b、左闭右开
while(left<right)
if(nums[middle]>target) right=middle;
数组长度:nums.size()
笔记:
注意最后 return-1
1.1.3 时间空间复杂度
暴力解法时间复杂度:O(n)
二分法时间复杂度:O(logn)
1.2 数组中移除元素(双指针法)(3.9)(3.25)()
vector中的rrase函数操作是O(n),而不是O(1)
把快指针指向的数值,赋给慢指针所在的位置
快指针:获取新数组的元素
慢指针:指向更新 新数组下标的位置
注意这些实现方法并没有改变元素的相对位置!
// 时间复杂度:O(n)
// 空间复杂度:O(1)
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
if (val != nums[fastIndex]) {
nums[slowIndex++] = nums[fastIndex];
}
}
return slowIndex;
}
};
1.2.1 时间空间复杂度
时间复杂度:O(n)
空间复杂度:O(1)
1.3 有序数组的平方(滑动窗口法)(03.10)(03.27)
sort(nums.begin(),nums.end());
sort排序函数,默认从小到大,从大到小需要加参数greater() 类似于快速排序的方法,时间复杂度为n*log2(n),执行效率较高
推荐双指针法
注意:
定义result的方法: vector result(nums.size(), 0);
1.3.1 时间空间复杂度
暴力解法时间复杂度:O(n^2)
滑动窗口时间复杂度:O(n)
1.4 长度最小的子数组(03.10)(3.29)()
int result = INT32_MAX; INT32_MAX 是 C++ 中定义的一个常量,表示 32 位有符号整数类型 (int32_t) 的最大值。在大多数系统中,INT32_MAX 的值通常是 2147483647 (2^31 - 1)。 通常,将一个变量初始化为 INT32_MAX 或者 INT_MAX (表示 int 类型的最大值)的做法, 是为了在后续的计算或比较过程中,方便地找到最小值或者更新结果值。 例如,在寻找一组数据中的最小值时,可以先将 result 初始化为 INT32_MAX,然后遍历这组数据,用 result 与每个数据元素进行比较,如果发现有比 result 更小的值,就用该值更新 result。最终,result 就会存储这组数据的最小值。
1.4.1 数组操作中的滑动窗口
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result=INT32_MAX; //
int sum = 0; // 子序列的数值之和
int subLength = 0; // 子序列的长度
int i=0; //滑动窗口起始值
for(int j=0;j<nums.size();j++)
{
sum=sum+nums[j];
while(sum>=target){
subLength=j-i+1; //子序列长度
result=result<subLength?result:subLength;
sum=sum-nums[i];
i++; //这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
}
}
//这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
return result== INT32_MAX ? 0 : result;
}
};
不要以为for里放一个while就以为是O(n^2)啊, 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。
1.5 螺旋矩阵II(3.11)(3.29)
注意循环不变量
四条边遍历的时候都遵循左闭右开的原则,就是矩阵的四个角都留给下一条边去处理
模拟顺时针画矩阵的过程:
填充上行从左到右
填充右列从上到下
填充下行从右到左
填充左列从下到上
在这里插入图片描述](https://img-
一共螺旋次数n/2,因为每转一圈上下减2,左右减2,所以一个螺旋次数n/2.
vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector创建了一个二维向量 res,有 n 行和 n 列,其中每个元素初始值为 0
int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组
int startx = 0, starty = 0; // 定义每循环一个圈的起始位置
int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)
int count = 1; // 用来给矩阵中每一个空格赋值
int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位
int i,j;
while (loop --) {
i = startx;
j = starty;
// 下面开始的四个for就是模拟转了一圈
// 模拟填充上行从左到右(左闭右开)
for (j = starty; j < n - offset; j++) {
res[startx][j] = count++;
}
// 模拟填充右列从上到下(左闭右开)
for (i = startx; i < n - offset; i++) {
res[i][j] = count++;
}
// 模拟填充下行从右到左(左闭右开)
for (; j > starty; j--) {
res[i][j] = count++;
}
// 模拟填充左列从下到上(左闭右开)
for (; i > startx; i--) {
res[i][j] = count++;
}
// 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
startx++;
starty++;
// offset 控制每一圈里每一条边遍历的长度
offset += 1;
}
// 如果n为奇数的话,需要单独给矩阵最中间的位置赋值
if (n % 2) {
res[mid][mid] = count;
}
return res;
}
};
1.5.1 时间空间复杂度
时间复杂度 O(n^2): 模拟遍历二维矩阵的时间
空间复杂度 O(1)
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/ff014fc23f3f433ba6e57ee83c244e5f.png