977.有序数组的平方
题目: 给你一个按 非递减顺序 排序的整数数组 nums
,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
链接: https://leetcode.cn/problems/squares-of-a-sorted-array/
思路:
- 暴力解法
先遍历一边平方,再排序。时间复杂度O(n+nlogn)即O(nlogn)。 - 双指针法
①定义一个新数组result
,大小与原数组一致,定义一个指针k
指向result数组的终止位置。
②定义两个指针i,j
,i
指向原数组最小值,j
指向原数组最大值。
③新数组排序规则:
A[i] * A[i] > A[j] * A[j]
,那么result[k--] = A[i] * A[i],i++
A[i] * A[i] < A[j] * A[j]
,那么result[k--] = A[j] * A[j],j--
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> res(nums.size());
int lowerPointer = 0;
int highPointer = nums.size() - 1;
for(int i = nums.size() - 1; i >= 0; i--){
if(nums[lowerPointer] * nums[lowerPointer] > nums[highPointer] * nums[highPointer]){
res[i] = nums[lowerPointer] * nums[lowerPointer];
lowerPointer++;
}
else{
res[i] = nums[highPointer] * nums[highPointer];
highPointer--;
}
}
return res;
}
};
时间复杂度:O(N)
空间复杂度:O(N)
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> res(nums.size());
int i = nums.size() - 1;
for(int lowerPointer = 0, highPointer = nums.size() - 1; lowerPointer <= highPointer;){
if(nums[lowerPointer] * nums[lowerPointer] > nums[highPointer] * nums[highPointer]){
res[i] = nums[lowerPointer] * nums[lowerPointer];
lowerPointer++;
i--;
}
else{
res[i] = nums[highPointer] * nums[highPointer];
highPointer--;
i--;
}
}
return res;
}
};
209.长度最小的子数组
题目: 给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
链接: https://leetcode.cn/problems/minimum-size-subarray-sum
思路: 滑动窗口
①定义一个指针end
,指向滑动窗口的终止位置。
②定义一个指针start
,指向滑动窗口的起始位置,当窗口内的子数组满足条件和 ≥ target
,再向后移动start指针,记录在此终止位置end
下的最短子数组长度。
③移动终止位置的指针end
。
注: 所求子数组为连续子数组,当start已经向后移动了,说明此时仍满足和 ≥ target
的条件,而不需要再考虑start之前的元素。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int ans = INT32_MAX;
int sum = 0;
int start = 0;
for(int end = 0; end < nums.size(); ++end){
sum += nums[end];
while(sum >= target){
ans = min(ans, end - start + 1);
sum -= nums[start];
start++;
}
}
return ans == INT32_MAX? 0 : ans;
}
};
时间复杂度:O(N)
时间复杂度主要看每一个元素被操作的次数,每个元素作为滑动窗口终止位置被操作一次,滑动窗口起始位置移动时被操作一次,所以时间复杂度是O(2*N)
。
空间复杂度:O(1)
59.螺旋矩阵II
题目: 给你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
链接: https://leetcode.cn/problems/spiral-matrix-ii/
思路: 循环不变量原则。
- 模拟顺时针画矩阵的过程:
①填充上行从左到右
②填充右列从上到下
③填充下行从右到左
④填充左列从下到上 - 每一行都要坚持左闭右开
![[Pasted image 20230112214027.png]]
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> res(n, vector<int>(n, 0));
int startx = 0;
int starty = 0;
int offset = 1;
int countIndex = 1;
int i = 0, j = 0;
int loop = n / 2;
while(loop--){
for(j = startx; j < n - offset; ++j){
res[startx][j] = countIndex++;
}
for(i = starty; i < n - offset; ++i)
res[i][j] = countIndex++;
}
for(j = n - offset; j > startx; --j){
res[i][j] = countIndex++;
}
for(i = n - offset; i > starty; --i){
res[i][j] = countIndex++;
}
offset++;
startx++;
starty++;
}
if(n % 2 == 1){
res[n / 2][n / 2] = countIndex;
}
return res;
}
};
总结: 遵循循环不变量的规则,一直左闭右开;时刻明确i,j
走到哪里了,确定其他相关变量的变化。
总结
数组考察题目常见类型
- 二分法
①循环不变量:左闭右开 / 左闭右闭;注意每一次二分left/right
的值如何处理。
②时间复杂度:O(logn) - 双指针
通过一个快指针和慢指针在一个for循环下完成两层for循环的工作。通常快指针用于快速遍历完整个数组,慢指针用来更新新的数组元素。 - 滑动窗口
滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置,将O(N^2)暴力解法的时间复杂度降为O(N)。 - 模拟行为
真正解决题目的代码都是简洁的,或者有原则性的。
注意遵循循环不变量的原则。
数组存储方式
数组存储在连续的内存空间中,且数组中的元素不能删除:
- 数组在内存中占用连续的地址空间,不能释放单一元素,如要释放,就要全释放(程序运行结束,回收内存栈空间)。
- vector是容器,底层实现是array。