977. 有序数组的平方 4分32
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
示例 1:
输入:nums = [-4,-1,0,3,10]
输出:[0,1,9,16,100]
解释:平方后,数组变为 [16,1,0,9,100],排序后,数组变为 [0,1,9,16,100]
示例 2:
输入:nums = [-7,-3,2,3,11]
输出:[4,9,9,49,121]
解题思想
根据上一次刷题的总结,采用的是对撞指针,设置 left 和 right 两个指针,left 在数组左端,right 在数组右端,分别比较 left 所指数组元素和 right 所指的数组元素的平方,较大者放入新数组(和所求数组一样长)的尾端。
为啥这样想呢?因为题中所给的是一个非递减的数组,平方之前最大的数在原数组的右端,但是由于负数的平方是正数且很可能平方之后大于原数组最大数的平方,因此,最左端的数平方之后也有可能成为新数组的最大值,所以考虑对撞指针,另外,由于每次遍历都是求最大的,所以采用倒序的方式为新数组赋值。
vector<int> sortedSquares(vector<int>& nums) {
int left = 0;
int right = nums.size() - 1;
vector<int> res = nums; // 新数组
int k = nums.size() - 1;
while (left <= right) { // 左闭右闭的原则
int a = nums[left] * nums[left];
int b = nums[right] * nums[right];
if (a > b) { // 取两数平方较大者
res[k--] = a;
++left;
}
else {
res[k--] = b;
--right;
}
}
return res;
}
收获:又是一道双指针的题,昨天是快慢指针,今天采用的是对撞指针,多用于解决有序数组或者字符串的问题。通过设置两个指针,一个从数组的起始位置开始,一个从数组的结束位置开始,相向移动。
209. 长度最小的子数组 33分59
给定一个含有 n 个正整数的数组和一个正整数 target 。找出该数组中满足其总和大于等于 target 的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
滑动窗口+解题思路
>>固定窗口大小(滑动窗口详解看这个)
由 left 和 right 两个指针所形成的区间,初始时 left 和 right 指向数组的同一个地址,然后 right 指针向右移动,sum 是 left 和 right 所围成的区间的和,当 sum >= target 时,right 不动,left 向右移动,缩小窗口范围来确定符合题目的最小长度。
本题需要在滑动窗口的模板上稍微改变下,增加对窗口值的判断,以用来求最小的长度。
int minSubArrayLen(int target, vector<int>& nums) {
// 数组总和小于 target
int sum = 0;
for (int i : nums) {
sum += i;
}
if (sum < target) return 0;
int left = 0, right = 0;
sum = 0; // 记录窗口值
int minLen = nums.size();
while (right < nums.size()) {
sum += nums[right++];
while (sum >= target) { // 满足条件,右边界停止移动
sum -= nums[left++]; // 左边界开始缩小
if (sum < target) { // 一旦不符合条件,更新窗口值
minLen = min(minLen, (right - left + 1));
}
}
}
return minLen;
}
收获:这道题我做的有点久了,而且还是第二次做,上一次的思路基本都忘光了。这道题我觉得还是考察快慢指针,快指针确定窗口的右边界,慢指针最终确定符合条件下的每一轮的最小长度,但是我更倾向于将其归类为固定窗口大小的滑动窗口,滑动窗口是第二次刷了,还需要总结一下。
54. 螺旋矩阵 没想到(;´༎ຶД༎ຶ`)
给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。
示例 1:
输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
示例 2:
输入:matrix = [[1,2,3,4],[5,6,7,8],[9,10,11,12]]
输出:[1,2,3,4,8,12,11,10,9,5,6,7]
说明:本来今天卡哥安排的是第 59.螺旋数组II ,但我觉得做之前可以先做下这道,自然就知道那道怎么写了
模拟算法
模拟算法是指:根据题目提供的信息,将该题目的解决过程模拟出来就能够得到最终的结果,模拟算法比较简单,只要能够根据题目的意思将题目给模拟出来,一般都能够解决这个问题。
根据以上描述我们就可以直到,直到模拟出螺旋矩阵的过程就可以得到最终的结果数组。
vector<int> spiralOrder(vector<vector<int>>& matrix) {
// 获取矩阵的行列
int m = matrix.size(), n = matrix[0].size();
int left = 0, right = n - 1;
int up = 0, down = m - 1;
// 结果数组
vector<int> result;
while (true) {
// 上右
for (int i = left; i <= right; i++) result.push_back(matrix[up][i]);
if (++up > down) break; // 上边界下移
// 右下
for (int i = up; i <= down; i++) result.push_back(matrix[i][right]);
if (--right < left) break; // 右边界左移
// 下左
for (int i = right; i >= left; i--) result.push_back(matrix[down][i]);
if (--down < up) break; // 下边界上移
// 左上
for (int i = down; i >= up; i--) result.push_back(matrix[i][left]);
if (++left > right) break; // 左边界右移
}
return result;
}
收获:其实这道题一开始我是想要是能够像题中说的和螺旋数组一样就可以了,但是写不出来,就去b站(指路)上看视频讲解,这才直到原来这一类的题目叫做模拟。第一次接触这个算法,算是学习了。其实这个题也挺考验代码能力的,主要是我那个模拟的过程写不出来,这就当是学习了。
59. 螺旋矩阵 II 这道题就直接贴个链接了,思路就是模拟出螺旋矩阵的过程
void createMatrix(vector<vector<int>>& matrix) {
// 获取矩阵的行列
int m = matrix.size(), n = matrix[0].size();
int left = 0, right = n - 1;
int up = 0, down = m - 1;
// 用于生成连续的数填充进矩阵
int k = 1;
while (true) {
// 上右
for (int i = left; i <= right; i++, k++) matrix[up][i] = k;
if (++up > down) break; // 上边界下移
// 右下
for (int i = up; i <= down; i++, k++) matrix[i][right] = k;
if (--right < left) break; // 右边界左移
// 下左
for (int i = right; i >= left; i--, k++) matrix[down][i] = k;
if (--down < up) break; // 下边界上移
// 左上
for (int i = down; i >= up; i--, k++) matrix[i][left] = k;
if (++left > right) break; // 左边界右移
}
}
// 模拟螺旋路径,螺旋式填充数组
vector<vector<int>> generateMatrix(int n) {
// 创建 n 行 n 列的数组 --- 忘记了
vector<vector<int>> matrix(n, vector<int>(n, 0));
// 生成螺旋矩阵 -- 根据 54.螺旋矩阵来写
createMatrix(matrix);
// 创建结果数组
vector<vector<int>> result;
// 过程数组
vector<int> path;
// 一行一行遍历得到结果
int up = 0, down = n - 1;
while (true) {
// 按行遍历
for (int i = 0; i < n; i++) path.push_back(matrix[up][i]);
// 写入结果
result.push_back(path);
// 清空过程数组
path.clear();
if (++up > down) break;
}
return result;
}