977. 有序数组的平方
暴力排序
class Solution {
public:
vector<int> sortedSquares(vector<int>& A) {
for (int i = 0; i < A.size(); i++) {
A[i] *= A[i];
}
sort(A.begin(), A.end()); // 快速排序
return A;
}
};
这个时间复杂度是 O(n + nlogn), 可以说是O(nlogn)的时间复杂度,但为了和下面双指针法算法时间复杂度有鲜明对比,记为 O(n + nlog n)。
双指针法
双指针思路:最大元素一定是在两边
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
// 双指针思想
vector<int> result(nums.size(), 0); // 创建整数向量(vector<int>),其大小与向量nums的大小相同,且所有元素都初始化为0
int k = nums.size()-1;
for(int i=0, j=nums.size()-1; i<=j; ) // i++, j--取决于两头的元素谁大
{
if(nums[i]*nums[i]>nums[j]*nums[j]){
result[k--] = nums[i]*nums[i];
i++;
}
else{
result[k--] = nums[j]*nums[j];
j--;
}
}
return result;
}
};
时间复杂度是 O(n)
209. 长度最小的子数组
滑动窗口
还是双指针的思想,但取双指针间的集合,更像是一个滑动窗口。
最重要的思路是如何移动起始位置
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
//滑动窗口:双指针间的集合
int result = nums.size();
int i = 0, sum = 0;
for(int j=0; j<nums.size(); j++){ // j是终止位置
sum += nums[j];
while(sum>=target){
int subL = j-i+1;
result = min(result, subL);
sum -= nums[i];
i++;
}
}
if(i==0) return 0; // 注意result没在循环里被赋值的情况
else return result;
}
};
- 时间复杂度:O(n)
- 空间复杂度:O(1)
为什么时间复杂度是O(n)。
不要以为for里放一个while就以为是O(n^2), 主要是看每一个元素被操作的次数,每个元素在滑动窗后进来操作一次,出去操作一次,每个元素都是被操作两次,所以时间复杂度是 2 × n 也就是O(n)。
59. 螺旋矩阵Ⅱ
循环不变量
注意四条边节点的处理 -> 统一处理方式,左闭右开
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
// 创建一个大小为n x n的全0矩阵
vector<vector<int>> nums(n, vector<int>(n, 0));
int startx = 0, starty = 0;
int i,j;
int loop = n/2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理
int offset = 1;
int count = 1; // 计数
while(loop--){
j=starty;
for(j = starty; j<n-offset; j++){
nums[startx][j] = count++;
}
i=startx;
for(i=startx; i<n-offset; i++){
// 此时j=n-offset
nums[i][j] = count++;
}
for( ; j>starty; j--){
nums[i][j] = count++;
}
for( ; i>startx; i--){
nums[i][j] = count++;
}
startx++;
starty++;
offset++;
}
if(n%2==1){
// nums[i][j]=count; // 注意n=1时这时i,j还没赋值
int mid = n/2;
nums[mid][mid] = count;
}
return nums;
}
};