学习《代码随想录》
- 理论基础
- 什么是数组?
- 二分查找
- 左闭右闭
- 左闭右开
- 移除元素
- 暴力法
- 双指针法
- 长度最小的子数组
- 暴力法
- 滑动窗口
- 螺旋矩阵
理论基础
什么是数组?
数组是存储在连续内存空间上的相同类型数据的集合。
二分查找
有两种解法:左闭右闭、左闭右开
左闭右闭
即 [ left , right ]
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size() - 1; //定义为左闭右闭
while (left <= right) { //见注1
//这一步等同于(left + right) / 2,如下处理为了防止内存溢出
int middle = left + ((right - left) / 2);
if (nums[middle] > target) { //说明target在左区间
right = middle - 1;
}else if (nums[middle] < target) {
left = middle + 1;
}else {
return middle;
}
}
return -1;
}
};
注
- 因为定义了左闭右闭,所以 left 可以取到 right ,用
<=
左闭右开
即 [ left , right )
class Solution {
public:
int search(vector<int>& nums, int target) {
int left = 0;
int right = nums.size(); //定义为左闭右开
while (left < right) { //left取不到right
int middle = left + ((right - left) / 2);
if (nums[middle] > target) {
right = middle; //左区间是[left,middle)
}else if (nums[middle] < target) {
left = middle + 1;
}else {
return middle;
}
}
return -1;
}
};
移除元素
两种解法:暴力法、双指针法
暴力法
用两层for循环向前覆盖元素
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int size = nums.size();
for (int i = 0; i < size; i++) { //第一个for循环遍历数组元素
if (nums[i] == val) {
for (int j = i + 1; j < size; j++) { //第二个for循环更新数组
nums[j - 1] = nums[j];
}
i--; //i后的元素都向前移了一位,所以i--
size--;
}
}
return size;
}
};
时间复杂度:O(n^2)
空间复杂度:O(1)
双指针法
用两个指针(快指针和慢指针)在一层for循环实现两层for循环的工作
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int slowIndex = 0;
for (int fastIndex = 0; fastIndex < nums.size(); fastIndex++) {
//若找到该元素,fastIndex++,slowIndex不动
if (nums[fastIndex] != val) {
//在下一次循环,用fastIndex指向的元素覆盖slowIndex的
nums[slowIndex] = nums[fastIndex];
slowIndex++;
}
}
return slowIndex;
}
};
时间复杂度:O(n)
空间复杂度:O(1)
长度最小的子数组
两种解法:暴力法、滑动窗口
暴力法
第一个for循环遍历所有元素,第二个for循环查找从该元素到数组末尾
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result = INT32_MAX; //结果
int sum = 0;
int subLength = 0; //记录最小长度
for (int i = 0; i < nums.size(); i++) {
sum = 0;
for (int j = i; j < nums.size(); j++) {
sum += nums[j];
if (sum >= target) { //一旦和大于target,记录最小长度
subLength = j - i + 1;
result = result < subLength ? result : subLength;
break;
}
}
}
return result == INT32_MAX ? 0 : result;
}
};
时间复杂度:O(n^2)
空间复杂度:O(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 += nums[j];
while (sum >= target) {
subLength = j - i + 1;
result = result > subLength ? subLength : result;
//滑动窗口的精髓,i一直在变
sum -= nums[i++];
}
}
return result == INT32_MAX ? 0 : result;
}
};
时间复杂度:O(n)
空间复杂度:O(1)
螺旋矩阵
坚持循环不变量:左闭右开
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0));
int startx = 0, starty = 0;
int loop = n / 2; //圈数,n=3时就一圈
int mid = n / 2; //如果n为奇数,最后要给中间位置赋值
int count = 1; //记录赋的值
int offset = 1; //控制每圈的长度,但不是长度
int i, j;
while (loop--) {
i = startx;
j = starty;
//四次循环就是一圈
for (j = starty; j < starty + n - offset; j++) {
res[startx][j] = count++;
}
for (i = startx; i < startx + n - offset; i++) {
res[i][j] = count++;
}
for (; j > starty; j--) {
res[i][j] = count++;
}
for (; i > startx; i--) {
res[i][j] = count++;
}
//每次循环后的处理
startx++;
starty++;
offset += 2;
}
//如果是奇数
if (n % 2) {
res[mid][mid] = count;
}
return res;
}
};