977、有序数组的平方
nums
,返回
每个数字的平方 组成的新数组,要求也按
非递减顺序 排序。
方法1:暴力
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
vector<int> vec;
for(int i = 0;i<nums.size();i++){
vec.emplace_back(nums[i]*nums[i]);
}
sort(vec.begin(),vec.end());
return vec;
}
};
方法2:双指针
由于是有序数组,所以平方之后,一定是两边的大中间的小,所以要比较两边的元素大小,在从大到小倒序填入到数组之中即可,时间复杂度为O(n)即可实现
注意:这里的左右指针一定是可以相等的,不然就丢失了最后一个数据。还有这个在数组中倒序添加元素的方法也要注意。
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int right = nums.size()-1;
int k = nums.size()-1;
int left = 0;
vector<int> ans(nums.size(),0);
while(left<=right){
if(nums[left]*nums[left]>=nums[right]*nums[right]){
ans[k] = nums[left]*nums[left];
k--;
left++;
}else {
ans[k] = nums[right]*nums[right];
k--;
right--;
}
}
return ans;
}
};
209、长度最小的子数组
给定一个含有 n
个正整数的数组和一个正整数 target
。
找出该数组中满足其总和大于等于 target
的长度最小的 连续子数组 [numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回 0
。
滑动窗口
滑动窗口时间复杂度是O(n),而不是O(n^2)
左右两个指针,右指针移动,sum记录元素和,当元素和大于等于目标值时,就要通过左指针右移实现窗口减小,同时sum要减去那个元素的值,记录最小的结果,这里不是只做一次判断,而是要多次判断,如果左指针移动一位后,还是不满足条件就要接着左移来缩小窗口,所以是while而不是if。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size();
//if(n == 0)return 0;
int left = 0,right = 0;
int sum = 0,ans = INT_MAX;
while(right<n){
sum +=nums[right];
while(sum>=target){
ans = min(ans,right-left+1);
sum-=nums[left];
left++;
}
right++;
}
return ans ==INT_MAX ?0:ans;
}
};
59.螺旋矩阵II
给你一个正整数 n
,生成一个包含 1
到 n2
所有元素,且元素按顺时针顺序螺旋排列的 n x n
正方形矩阵 matrix
。
模拟:一开始从左往右填充,填完之后就不在调整第一行,up++
接着在右边从上往下填充,填完之后,最右侧那一列就不再动,right--
在底边从右向左填充,填完之后,最下面那一行不再动,down--
在左边从下往上填充,填完之后,最左边那一列不再动,left++
由此就将第一圈全部填充完毕,再继续缩小范围,知道数字达到目标值就结束
class Solution {
public:
vector<vector<int>> generateMatrix(int n) {
vector<vector<int>> ans(n,vector<int>(n,0));
int left = 0,right = n-1;
int up = 0,down = n-1;
int count = 1,target = n*n;
//for循环中变量定义成i或j的细节:按照通常的思维,i代表行,j代表列
//这样,就可以很容易区分出来变化的量应该放在[][]的第一个还是第二个
//对于变量的边界怎么定义:
//从左向右填充:填充的列肯定在[left,right]区间
//从上向下填充:填充的行肯定在[up,down]区间
//从右向左填充:填充的列肯定在[right,left]区间
//从下向上填充:填充的行肯定在[down,up]区间
//通过上面的总结会发现边界的起始和结束与方向是对应的
while(count<=target){
//从左向右填充
for(int i = left;i<=right;i++){
ans[up][i] = count;
count++;
}
//缩小上边界
up++;
//从上往下填充
for(int i = up;i<=down;i++){
ans[i][right] = count;
count++;
}
//缩小右边界
right--;
//从右往左填充
for(int i = right;i>=left;i--){
ans[down][i] = count;
count++;
}
//缩小下边界
down--;
//从下往上填充
for(int i = down;i>=up;i--){
ans[i][left] = count;
count++;
}
//缩小左边界
left++;
}
return ans;
}
};
总结
数组经典题目:二分,双指针,滑动窗口,模拟
二分法:
左闭右闭
左闭右开
双指针:
都从左开始移动的双指针
一左一右的双指针
滑动窗口:
时间复杂度O(n)
模拟:
注意边界值