代码随想录训练营第二天|977.有序数组的平方,209.长度最小的子数组,59.螺旋矩阵II
977.有序数组的平方
力扣977.有序数组的平方
这道题是用到双指针的思想,只不过是从左右开始。
while(left<=right){
if(nums[left]*nums[left]>nums[right]*nums[right]){
n[length]=nums[left]*nums[left];
left++;//左侧平方大时用次数填充,移动左侧
}
else {
n[length]=nums[right]*nums[right];
right--;
}
length--;
}
209.长度最小的子数组
也称为滑动窗口。
209.长度最小的子数组
先确定循环终止的条件:
窗口的起始位置or终止位置?
如果是起始位置的话,那就相当于暴力算法中的每次移动起始位置i;
所以应该是以终止位置为基准判断。
for(;end<nums.size();end++){//当窗口内的值小于target时,向右移动窗口
sum+=nums[end];
while(sum>=target){//用while保证一直减到不能减为止
int length=end-start+1;
min=length<min?length:min;
sum-=nums[start];
start++;
}
}
904.水果成篮
`
int max;
int length=fruits.size();
int left=0,right=1;//这里是左开右闭的写法,即[left,right)为我们需要的区间
int first_fruit=fruits[0],second_fruit=fruits[1];
//保证第一种类型的水果和第二种类型的水果一定不一样
while(first_fruit==second_fruit&&right<length){
second_fruit=fruits[right];
right++;
max=right-left;//因为right++后,right前的一定在果篮中,所以先移动right再算max;
}
while(right<length){
while(right<length&&(fruits[right]==first_fruit||fruits[right]==second_fruit)){
//要写right<length不然可能会范围溢出,而且要写在最前面(与逻辑运算的短路有关)
right++;//当确定边界处的水果是第一二种类型时(此时不在范围内),移动边界
max=(right-left)>max?right-left:max;//用三目运算符更新max;
}
if(right<length&&(fruits[right]!=first_fruit&&fruits[right]!=second_fruit)){
//当边界处是第三种类型的水果时
second_fruit=fruits[right];//将其记录为第二种类型的水果
left=right-1;
first_fruit=fruits[left];
while(fruits[left-1]==first_fruit){//向前寻找相同的水果
left--;
}
}
}
return max;
}
};
之前就写过一次,再写的时候思路还是正确的,只是有点绕。
用while向前寻找相同水果是看了别人的题解学会的,感觉很巧妙。
这题也要用到开区间防止范围溢出。
59.螺旋矩阵II
59.螺旋矩阵2
这题就是一直绕啊绕啊绕;
首先是生成二维数组,之前没学过容器,记一下这种写法:应该是 array(个数,填充的东西)
vector<vector<int>> array(n,vector<int>(n,0));
太久没写二维数组,一开始还把x,y写反了,应该是array [y] [x];
循环中要坚持不变量原则,本题坚持左闭右开。
边界又与圈数有关,圈数不超过n/2;
截取一小段代码
for (int qs=1;qs <= n/2;qs++){
for(;x<n-qs;x++){
array[y][x]=number;
number++;
//。。。
}
关于是矩形的矩阵问题:
54.螺旋矩阵
也可以用相同的思路来
int m=matrix.size();
int n=matrix[0].size();
vector<int> array (m*n,0);
int x=0,y=0;
int qs=1;
int number=0;
for(;qs<=n/2&&qs<=m/2;qs++){
for(;x<n-qs;x++){
array[number++]=matrix[y][x];
}
for(;y<m-qs;y++){
array[number++]=matrix[y][x];
}
for(;x>qs-1;x--){
array[number++]=matrix[y][x];
}
for(;y>qs-1;y--){
array[number++]=matrix[y][x];
}
x++;
y++;
}
只不过最后中间有可能会剩下1n或n1的矩阵还要处理:
1.如果n>m且m有奇数行,则会剩下1n的横矩形;
2.如果m>n且n有奇数列,则会剩下n1的竖矩形;
3.m==n且为奇数,剩一个
if(m%2==1&&n==m){
array[number]=matrix[y][x];
}
else if(n>m&&m%2==1){
for(;x<n-qs+1;x++){
array[number++]=matrix[y][x];
}
}
else if(n<m&&n%2==1){
for(;y<m-qs+1;y++){
array[number++]=matrix[y][x];
}
}
另一种方法(通法)
按照边界来处理
每次处理的变量不一样
这样的好处是不用再讨论剩余的矩形
注意在处理下和左的时候要先看看边界是什么情况,比如如果再n次处理后
top=bottom,那直接处理下和左就会进行重复操作。
1.
这里可以在每次处理完一条边后直接更新边界,比如图中红色边处理完后直接更新top值
for(int i=left;i<=right;i++){
array[number++]=matrix[top][i];
}
top++;
if(top>bottom)
break;
如果top++后大于bottom,说明原本上下边界重合了,只剩1*n的矩形,就没必要再处理。
2.
每次处理完四条边后一起进行top++,right–,bottom++,left++;
这样处理需要再处理下和左时考虑边界是否有重合
if(left<=right&&top<=bottom){
for(int i=right;i>=left;i--){
array[number++]=matrix[bottom][i];
}
//.....
比较两种方法:前者遵循不变量,但最后需要对m,n进行讨论
后者上下左右的变量范围不一样,但仍遵循边界原则,且不用分类讨论。