代码随想录Day2| 977.有序数组的平方209.长度最小的子数组 59.螺旋矩阵II

代码随想录|704.二分查找、27.移除元素

有序数组的平方

文档讲解:代码随想录
视频讲解:LeetCode:977.有序数组的平方
状态:能做

  1. 思路
    之后刷的时候用各种排序算法写一下。
    主要还是利用双指针,考虑到负数和正数,在平方后可能出现大小颠倒的情况,所以需要寻找一个分割线,然后利用两个指针来判断两段中的数的大小,较小的填入返回数组,并移动下标。
    分割线就是第一个不小于0的数。但这种方法还需要注意全是负数的情况
class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        //获取第一个大于等于0的数
        int middle = -1;
        for(int i=0;i<nums.size();i++)
        {
            if(nums[i]>=0)
            {
                middle = i;
                break;
            }
        }

        //判断全是负数的情况,最终结果是倒序
        if(middle == -1)
        {
            middle = nums.size();
        }

        //定义两个指针,一个从最大的负数开始middle-1,一个从最小的非负数开始middle
        int pt1 = middle-1;
        int pt2 = middle;

        //当pt1>=0并且pt2<size的时候进行判断,并填入返回的数组
        //当有一个超出了限制,则将剩下的另一个全部填入数组依序。
        vector<int> res(nums.size());
        int k = 0;
        while(pt1>=0&&pt2<nums.size())
        {
            if(nums[pt1]*nums[pt1] > nums[pt2]*nums[pt2])
            {
                res[k] = nums[pt2]*nums[pt2];
                k++;
                pt2++;
            }
            else
            {
                res[k] = nums[pt1]*nums[pt1];
                k++;
                pt1--;
            }
        }

        //将剩下的填入
        while(pt1>=0)
        {
            res[k] = nums[pt1]*nums[pt1];
            k++;
            pt1--;
        }
        while(pt2<nums.size())
        {
            res[k] = nums[pt2]*nums[pt2];
            k++;
            pt2++;
        }

        return res;
    }
};
  1. 代码随想录方法
    利用头指针和尾指针向中间收缩,注意两头的值肯定是平方后的最大值,所以返回数组的填写需要通过倒序填写。并且循环处理的终止条件是左指针大于右指针,因为两个指针同时指向的值也需要填入,一般为最小值。
class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        vector<int> res(nums.size());
        int left = 0;
        int right = nums.size()-1;
        int k = nums.size()-1;
        for(left,right;left<=right;)
        {
            if(nums[left]*nums[left]>=nums[right]*nums[right])
            {
                res[k] = nums[left]*nums[left];
                k--;
                left++;
            }
            else
            {
                res[k] = nums[right]*nums[right];
                k--;
                right--;
            }
        }
        return res;
    }
};

长度最小的子数组

文档讲解:代码随想录
视频讲解:拿下滑动窗口! | LeetCode 209 长度最小的子数组
状态:85%

  1. 思路
    连续子数组,相当于用一个子数组去框选长度最小满足条件的范围,首先确定头和尾就使用两个指针,当和一直小于target那么就移动尾指针,如果和大于等于target后就向前移动头指针,并减去之前的头指针指向的位置。
    之前我的写法没有用while判断,导致头尾指针的移动在一起(错误),减枝不好处理。后来学习过后,利用while处理头指针的移动,使得头尾指针的移动能够分开来进行。
    当和一直大于等于target移动头指针,当和小于target移动尾指针
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        //数组长度记录
        int count = 0;

        //头指针,当sum>=target时移动
        int left = 0;

        //尾指针,当sum<target时移动
        int right = 0;

        //和,当小于target时由right控制,大于等于targte时由left控制
        int sum = 0;

        
        while(right<nums.size())
        {
            sum += nums[right];
                while(sum>=target)
                {
                    if(count > right-left+1 || count == 0)
                    {
                        count = right-left+1;
                    }
                    sum -= nums[left++];
                }
            right++;
        } 
        return count;       
    }
};

螺旋矩阵II

文档讲解:代码随想录
视频讲解:一入循环深似海 | LeetCode:59.螺旋矩阵II
状态:不会

  1. 思路
    一个螺旋就是一个循环,从外层向里依次填入数据。主要需要思考的问题有以下几点
    1. 循环的次数:n/2
    2. 新循环的起点:最开始是0,0,循环一次后是1,1,所以需要每次循环完进行+1操作
    3. 每次循环每条边的填充长度控制:最开始是n-1个位置都需要填,第二次是n-2,所以每次循环完之后进行-1操作
    4. 奇数n的中间数操作:对于奇数n,中间数一定是他的平方数,而对于偶数n不存在,所以利用mod2来判断是否是奇数
    5. 填充操作:首先要注意不能重复填充,特别是每层循环的4个角位置,如果我们对填充操作的边界是<=或者>=那么肯定会出现重叠,所以应该选择左闭右开的方式来进行填充。其次是每次填充由右向左进行填写时,注意边界,应当是当前的起点坐标对应的x,y值。
class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        //0,0 -> 0,n-1        [0,n-1) ->
        //0,n-1 -> n-1,n-1    [0,n-1)  ⬇
        //n-1,n-1 -> n-1,0    [n-1,0) <-
        //n-1,0 -> 0,0        [n-1,0) ⬆
        int size = n-1;
        vector<vector<int>> res(n,vector<int>(n));

        //起始位置
        int numx = 0;
        int numy = 0;

        //填充循环数
        int loop = n/2;
        //填充数
        int i = 1;
        
        //每条边的长度控制
        int k = 1;

        while(loop--)
        {
            //每条边的填入位置控制
            int a = numx;
            int b = numy;
            //-> x=0 , y[0,n-1)
            for(b;b<n-k;b++)
            {
                res[a][b] = i++;
            }
            //⬇ y=n-1 , x[0,n-1)
            for(a;a<n-k;a++)
            {
                res[a][b] = i++;
            }
            //<- x=n-1 , y[n-1,0)
            for(b;b>numx;b--)
            {
                res[a][b] = i++;
            }
            //⬆ y=0 , x=[n-1,0)
            for(a;a>numy;a--)
            {
                res[a][b] = i++;
            }

            //一层做完,更新起始位置和循环边的长度
            numx++;
            numy++;
            k++;
        }

        //考虑n为奇数,那么最中间的数就是n²
        if(n%2)
        {
            res[n/2][n/2] = n*n;
        }

        return res;
    }
};

时间复杂度:k(n-1+n-2+…+1) = O( n 2 n^2 n2)

螺旋矩阵

  1. 思路
    本题和上一题相似,具体两点区别
    1. 一个是二维变一维,一个是一维变二维
    2. 这道题的边长不相等了。
      第一个变化很容易解决,就是在循环中把赋值操作换一下,第二点就需要更多的判断了以及设计到循环次数的控制。
      使用m/2和n/2较小的数作为循环次数,这样在循环完成之后,只会剩下1列或者1行,直接读入就可以了。其次在最后读入的时候还需要考虑现在是不是已经读取完毕了,比如对于3行2列的情况,在1次循环过程中已经可以满足所有的数据读入。
class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {

        //行数
        int m = matrix.size();
        //列数
        int n = matrix[0].size();

        int loop = m<n?m/2:n/2;

        //返回数组
        int k = 0;
        vector<int> res(m*n);

        //循环读取
        int numx = 0;
        int numy = 0;
        int check = 1;



        while(loop--)
        {
            int i = numy;
            int j = numx;

            //-> i=0 j[0,n-1)
            for(j;j<n-check;j++)
            {
                res[k++] = matrix[i][j];
            }

            //⬇ j=m-1 i[0,m-1)
            for(i;i<m-check;i++)
            {
                res[k++] = matrix[i][j];
            }

            //<- i=m-1 j[n-1,0)
            for(j;j>numy;j--)
            {
                res[k++] = matrix[i][j];
            }
            
            //⬆ j = 0, i[n-1,0)
            for(i;i>numx;i--)
            {
                res[k++] = matrix[i][j];
            }

            numx++;
            numy++;
            check++;
        }
        //正方形奇数矩阵,读取最后一个数
        if(m==n && m%2)
        {
            res[k] = matrix[m/2][n/2];
        }

        //其他普通矩阵,读取剩余的列(行数为m/2)或者行(列数为n/2)
        //需要注意的是,目前应当采用[]区间,因为要获得最后一个数
        //具体的逻辑,可以考虑如何读取只有1行或者1列的方法。
       if(m>n)
       {
           for(int i=numx;i<=m-check;i++)
           {
               if(k<m*n){
                   res[k++] = matrix[i][n/2];
               } 
           }
       }
       if(m<n)
       {
           for(int j = numy;j<=n-check;j++)
           {
               if(k<m*n)
               {
                   res[k++] = matrix[m/2][j];
               }
           }
       }
       return res;
    }
};
  • 6
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值