题目1:977. 有序数组的平方 - 力扣(LeetCode)
整体思路:因为可能有负数的存在,平方之后并不一定程递增。所以采用左右双指针法。
将左右所指位置的平方值进行比较,较大者赋给res数组,所以res数组是从结尾往开头进行填充的。
left = right是最后一次循环,所以while(left<=right)
当左右两个位置的平方值相等时,取谁都行了,所以判断的时候不需要单独考虑左平方值等于右平方值的情况
class Solution {
public:
vector<int> sortedSquares(vector<int>& nums) {
int left = 0;
int right = nums.size()-1;
vector<int> res(nums.size(),0);
int i = nums.size()-1;
while(left<=right){ // left right可以取等,因为当left>right时才能把所有元素平方值都填充完
if(nums[left] * nums[left] >= nums[right]*nums[right]){
res[i] = nums[left] * nums[left];
i--;
left++;
}else{
res[i] = nums[right] * nums[right];
i--;
right--;
}
}
return res;
}
};
题目2:209. 长度最小的子数组 - 力扣(LeetCode)
整体思路:用快指针指向当前子数组的最顶端,在每个循环里都要快指针++,但是同样也要在每个循环里持续判断当前子数组元素和与目标值的大小关系。
注意本题是找>=target的最小子数组长度,所以while的条件sub>=target。如果找=target的最小子数组,需要在while里再判断=target的情况,如下面代码的注释部分。
res初始化可以用INT32_MAX
最开始我的第一反应也是用快指针做遍历,但是在循环里面分别去判断子数组元素和与target大于、小于、等于的关系,但是实现起来很麻烦,虽然也能实现当sub>target时持续的把左指针左移,但是代码麻烦了很多,最后不了了之。看了卡哥的代码重新实现了一下。
int minSubArrayLen(int target, vector<int>& nums) {
int left = 0;
int right = 0;
int sub = 0;
int len = 0;
int res = INT32_MAX;
for (; right<nums.size(); right++) {
sub += nums[right];
while (sub >= target) {
/*
// 如果找和恰好等于target的数组用这段
if(sub==target){
res = min(res,right-left+1);
}
*/
len = right - left + 1;
res = min(res, len);
sub -= nums[left];
left++;
}
}
return res == INT32_MAX ? 0 : res; // 如果res ==INT32_MAX,则返回0,否则返回当前res值
}
题目3:59. 螺旋矩阵 II - 力扣(LeetCode)
整体思路:去控制每一圈的开始位置和截止位置,圈数由n来决定,所以计算loop = n/2。在每一圈的开始,用startx,starty去赋值i,j,在每一条边的结尾用offeset去控制,也就是<n-offset。这样去逐个赋值每条边,达到每一圈一个循环的效果。
循环不变量原则---每一条边都是左闭右开。依此来设计offset和n-offset
startx,starty的设计很巧妙。我最开始想要去在每一边开始时计算起始位置,其实不用这么麻烦,用startx,starty,先初始化为0,再在每一圈++就可以了。
填充元素用count++
每一条边结束之后,可以继续使用上一条边的到的遗留i或j的数值。原先本以为for循环一结束,i,j就清除,但实际上这道题是在while循环开始前就初始化了i和j,所以不会导致for循环一结束,ij就被删除。
最后记得要判断n是奇数还是偶数。如果是奇数,螺旋矩阵中间的点需要另外赋值。
vector<vector<int>> generateMatrix(int n) {
// 先写n为奇数情况
int loop= n/2;
int i=0;
int j=0;
int offset=1;
int cout = 1;
int startx = 0;
int starty = 0;
vector<vector<int>> res(n,vector<int>(n,0)); // 一定要初始化,否则报错
while(loop--){
i = startx;// 很巧妙,去记录开始位置这样来控制每个边
j = starty;
for(j = starty;j<n-offset;j++) {
res[i][j]=cout;
cout++;
}
for(i = startx;i<n-offset;i++){
res[i][j]=cout;
cout++;
}
for(;j>starty;j--){
res[i][j]=cout;
cout++;
}
for(;i>startx;i--){
res[i][j]=cout;
cout++;
}
offset++;
startx++;
starty++;
}
if(n%2 == 1 ){
int mid = n/2;
res[mid][mid] = cout;
}
return res;
}
总结:第二天刷题,三道题之前跟着卡尔的视频做过,所以比上次快了不是一星半点。
第一道题一遍就做出来了。
第二题大致思路对,但是实现方法有些繁琐,最后参考卡尔的方法改正。
第三道题其中的循环不变量思想,loop、offset、startx,starty的引入很巧妙,需要触类旁通,多加练习。