代码随想录训练营第二天|977.有序数组的平方,209.长度最小的子数组,59.螺旋矩阵II

代码随想录训练营第二天|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有奇数列,则会剩下n
1的竖矩形;
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进行讨论
后者上下左右的变量范围不一样,但仍遵循边界原则,且不用分类讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值