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

1.4 977.有序数组的平方

注意题目说这个数组是整数数组,里面可能是有负数的,题目也没有对空间复杂度的要求

最直白的想法:把所有元素平方之后再进行排序(快排),但是这种方式的时间复杂度是O(nlogn)

O(n)的解题方法:双指针法

这个题对空间复杂度没有要求,所以可以定义一个新的数组用来存储结果数组

那这个题是怎么想到用双指针法来做的呢?就是这个数组的特性,他在平方之后的大小变化趋势是两端的数值是最大的,都向中间递减

注意:这里循环条件是pre≤after(其实也是因为区间是左闭右闭得),因为如果不加等于,那就是在这俩指针相等的时候这个循环直接退出了,那就是会把这个元素给落下,但是这个元素也得放在最后的result数组中啊,所以就得小于等于

易错点:

  • left和right、以及index都要动(容易忘记移动)

1.5 209.长度最小的子数组

暴力法:两层for循环,遍历出所有子序列的情况

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        //暴力法
       int min=nums.length;
       int len=0;
       boolean exist=false;
        //外层循环控制初始位置
        for(int i=0;i<nums.length;i++){
            int sum=0;
            //内层循环控制终止位置
            for(int j=i;j<nums.length;j++){
              sum+=nums[j];
            if(sum>=target){
                exist=true;
                len=j-i+1;
                break;
            }
            }
            if(min>len){
                min=len;
            }
        }
        if(!exist){
            return 0;
        }
        return min;
    }
}

滑动窗口法:和之前的双指针思路类似,也是由两个指针进行操作,只不过我们是取两个指针中间的集合

其实是用一个for循环来做两个for循环所做的事情

但是用下面的思路即使是让for循环滑动窗口的终止位置,力扣还是会显示超出时间限制

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        //滑动窗口法(和双指针类似)
        //当窗口中的和大于target时,left移动;
        //当窗口中的和小于target时,right移动;
        //记录大于等于target的长度
        int left=0;
        int sum=0;
        int min=nums.length;
        int len=0;
        boolean isExist=false;
        for(int right=0;right<nums.length;right++){
            sum=0;
            for(int i=left;i<=right;i++){
                sum+=nums[i];
            }    
            if(sum>=target){
                len=right-left+1;
                left++;
                right--;
                isExist=true;
                if(len<min){
                    min=len;
                }
            }
            
        }
        if(isExist) return min;
        else return 0;
    }
}   

改进之后:求窗口内数字元素的和不要用内层循环求,而是直接求,然后滑动窗口的时候,在原来和的基础上+或-就行

class Solution {
    public int minSubArrayLen(int target, int[] nums) {
        //滑动窗口法(和双指针类似)
        //当窗口中的和大于target时,left移动;
        //当窗口中的和小于target时,right移动;
        //记录大于等于target的长度
        int left=0;
        int sum=0;
        int min=nums.length;
        int len=0;
        boolean isExist=false;
        for(int right=0;right<nums.length;right++){
        sum+=nums[right];
        if(sum>=target){
            isExist=true;
            //right不动,left动;并记录长度
            len=right-left+1;
            if(len<min){
                min=len;
            }
            sum-=nums[left];
            left++;
            sum-=nums[right];
            right--;
        }
            
        }
        if(isExist) return min;
        else return 0;
    }
}

以上思路的要点/易错点:

  1. 求窗口内数字的和不要用循环,在外层循环求,当窗口滑动时,在原来和的基础上加或减就行

  2. 当判断和大于等于target,窗口要开始移动时,集左指针要向右移动,右指针不能动,但因为外循环右指针必然会++,所以这里right还要--,并且在sum中也减去nums[right]的值

主要步骤:

  1. 定义滑动窗口的边界

  2. 求窗口内数字元素的和

  3. 判断和是否≥target

    • 大于/等于:滑动窗口

    • 小于:正常移动右指针,再求和,再判断

1.6 59.螺旋矩阵Ⅱ

class Solution {
    public int[][] generateMatrix(int n) {
        int[][] result=new int[n][n];
        //先得到共有多少层(-1)
        int levelNum=n/2;
        int num=1;
        for(int i=0;i<levelNum;i++){
            for(int j=i;j<(n-1-i);j++){
                result[i][j]=num;
                num++;
            }
            for(int j=i;j<(n-1-i);j++){
                result[j][n-1-i]=num;
                num++;
            }
            for(int j=(n-i-1);j>i;j--){
                result[n-i-1][j]=num;
                num++;
            }
            for(int j=(n-i-1);j>i;j--){
                result[j][i]=num;
                num++;
            }
        }
        if(n%2!=0){
           
             result[n/2][n/2]=num;
         } 
        return result;
    }
}

注意:错误的地方在于当n是奇数时,最后一圈只剩了一个元素

class Solution {
    public int[][] generateMatrix(int n) {
        int levelNum=n/2+1;
        int[][] result=new int[n][n];
        int num=1;
        //注意:这里循环条件是小于,因为如果有等于,当n是偶数时,就会多循环一圈
        //但是小于的话,当n等于奇数时又会少循环一圈,所以要在后面补n为奇数时,最后剩下的一个数
        for(int i=1;i<levelNum;i++){//i是层数
        //上:行:层数-1;列:[层数-1;n-层数-1]
        for(int j=(i-1);j<=(n-i-1);j++){
            result[i-1][j]=num;
            num++;
        }
        //右:行:[层数-1,n-层数-1];列:n-层数
        for(int j=(i-1);j<=(n-i-1);j++){
            result[j][n-i]=num;
            num++;
        }
        //下:行:n-层数;列:[n-层数,层数+1-1]
        for(int j=(n-i);j>=i;j--){
            result[n-i][j]=num;
            num++;
        }
        //左:行:[n-层数,层数+1-1];列:层数-1
        for(int j=(n-i);j>=i;j--){
            result[j][i-1]=num;   
            num++;        
        }
        }
        if(n%2!=0){
            result[n/2][n/2]=num;
        }
        return result;
    }
}

注意:

  • 变化的行数和列数之间有连续的关系

易错点:

  1. 填充的数是1-n^2,而不是每个都要平方

  2. 注意所在层数和数组下标的关系(下标是从0开始的)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值