一、知识点
1、创建数组
1)vector<int> arr(nums.size(), 0);
创建了一个整数类型的vector(通常称为一维数组或向量),并将其大小初始化为nums.size(),同时将所有元素初始化为0。
2)vector<vector<int>> res(n, vector<int>(n, 0));
创建了一个 n x n 的二维整数向量(矩阵),并将所有元素初始化为0。
vector<int>(n, 0)
:这部分创建了一个大小为n
的一维整数向量,并将所有元素初始化为0。vector<vector<int>> res(...)
:这部分创建了一个二维整数向量res
。res(n, vector<int>(n, 0))
:这表示res
是一个包含n
个元素的二维向量,其中每个元素都是一个由vector<int>(n, 0)
创建的一维向量。
二、题目
977. 有序数组的平方
题目链接:https://leetcode.cn/problems/squares-of-a-sorted-array/
做题思路
数组平方的最大值就在数组的两端,不是最左边就是最右边,不可能是中间。
总体思路:使用双指针法,i 指向起始位置,j 指向终止位置。比较数组两端平方的最大值
如果 i 所在的值大,用 i 的下一位比;如果 j 所在的值大,用 j 的前一位比
代码细节
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int max, i, j;
// 返回 每个数字的平方 组成的新数组arr
vector<int> arr(nums.size(), 0);
// 新数组长度 同 整数数组 nums
int p = nums.size() - 1;
// 数组平方的最大值就在数组的两端
// i 指向起始位置,j 指向终止位置,比较数组两端平方的最大值
for(i = 0, j = nums.size() - 1; i <= j;)
{
// 找到数组平方的最大值
if(nums[i] * nums[i] > nums[j] * nums[j])
{
max = nums[i] * nums[i];
// 如果 i 所在的值大,用 i 的下一位比
i++;
}
else
{
max = nums[j] * nums[j];
// 如果 j 所在的值大,用 j 的前一位比
j--;
}
// 把最大值赋值给新数组
arr[p] = max;
p--;
}
return arr;
}
};
209. 长度最小的子数组
题目链接:https://leetcode.cn/problems/minimum-size-subarray-sum/
视频讲解:https://www.bilibili.com/video/BV1tZ4y1q7XE
文章讲解:https://programmercarl.com/0209.%E9%95%BF%E5%BA%A6%E6%9C%80%E5%B0%8F%E7%9A%84%E5%AD%90%E6%95%B0%E7%BB%84.html
做题思路
1)滑动窗口,就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果。
滑动窗口也可以理解为双指针法的一种!只不过这种解法更像是一个窗口的移动,所以叫做滑动窗口更适合一些。
2)在本题中实现滑动窗口,主要确定如下三点:
- 窗口内是什么?
- 如何移动窗口的结束位置?
- 如何移动窗口的起始位置?
窗口就是 满足其和 ≥ target 的长度最小的 连续 子数组。
窗口的结束位置就是外层for循环的 j 。
如果当前窗口的值大于等于 target 了,窗口就要向前移动了(也就是 i 该更新了,窗口该缩小了)。
3)总体思路:先找窗口的终点,再缩小窗口,找窗口的起点(必须满足其和 ≥ target )
代码细节
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int min_len = INT32_MAX;
int len = 0;
int sum = 0;
int i = 0;
// j为终点,找到窗口的终点
for(int j = 0; j < nums.size(); j++)
{
sum += nums[j];
// i为起点,找到窗口的起点。找到总和大于等于 target 的长度最小的子数组
while(sum >= target)
{
// 更新长度
len = j - i + 1;
// 找到最小长度
if (len < min_len) min_len = len;
// 难点:缩小窗口,更新总和
sum -= nums[i];
// 更新窗口的起点
i++;
}
}
// 特殊情况:如果 min_len 依旧为初值,那么说明不存在符合条件的子数组
if(min_len == INT32_MAX) return 0;
else return min_len;
}
};
59. 螺旋矩阵
题目链接:https://leetcode.cn/problems/spiral-matrix-ii/
做题思路
1)如果要写出正确的二分法一定要坚持循环不变量原则。
区间的定义就是不变量。要在二分查找的过程中,保持不变量,就是在while寻找中每一次边界的处理都要坚持根据区间的定义来操作,这就是循环不变量规则。
写二分法,区间的定义一般为两种,左闭右闭即[left, right],或者左闭右开即[left, right)。
2)总体思路:模拟转圈+赋值。坚持每条边左闭右开的原则。
代码细节
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
// 创建一个零矩阵
vector<vector<int>> res(n, vector<int>(n, 0));
// 定义每次循环圈的起始位置
int start_x = 0, start_y = 0;
// 螺旋矩阵循环几次圈。例如n为奇数3,那么loop = 1
int loop = n / 2;
// n为奇数时,矩阵中间的位置。例如n为5,中间位置为(2, 2)
int mid = n / 2;
// 计数
int cnt = 1;
// 偏移量。offset 控制每一条边遍历的长度
int offset = 1;
// 转圈+赋值
while (loop--)
{
int i = start_x;
int j = start_y;
// 模拟转圈,坚持每条边左闭右开的原则
// 上行,i不变,都是第 i 行
for (j; j < n - offset; j++)
{
res[i][j] = cnt;
cnt++;
}
// 右列,j不变,都是第 j 列
for (i; i < n - offset; i++)
{
res[i][j] = cnt;
cnt++;
}
// 下行,i不变,都是第 i 行,等于start_y
for (; j > start_y; j--)
{
res[i][j] = cnt;
cnt++;
}
// 左列,j不变,都是第 j 列
for (; i > start_x; i--)
{
res[i][j] = cnt;
cnt++;
}
// 开始第二圈,起始位置更新,偏移量更新
// 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)
start_x++;
start_y++;
offset++;
}
// 特殊情况:如果n为奇数,需要单独给矩阵最中间的位置赋值
if(n % 2) res[mid][mid] = cnt;
return res;
}
};