训练营第二天 |力扣 977、有序数组的平方(双指针) 209、长度最小的子数组 (滑动窗口) 59、螺旋矩阵(模拟)

1、有序数组的平方(含负数)

思路:这题用双指针的思路可以实现O(n)复杂度的代码。因为当数组中可能存在负数并且数组有序的时候,它的元素的平方的大小一定是从两端向中间呈递减趋势的,然后只需要取较大值放入新数组中即可。

KEY:循环继续的条件:应该是left<=right,如果是小于的话当left=right时,循环跳出,那么就会漏掉原数组中的元素

总结:相比于先求值再快排,双指针可以获得更小的时间复杂度

代码:

class Solution {
public:
    vector<int> sortedSquares(vector<int>& nums) {
        vector<int>result(nums.size(),0);//要想下面成功放入元素,这里需要提前开辟内存
        int k=nums.size()-1;
        int i=0;
        int j=nums.size()-1;//用双指针来做,考虑负数时,两边向中间靠的平方是由大到小排列的
        for(;i<=j;)
        {
            if(nums[i]*nums[i]>nums[j]*nums[j])
            {
                result[k]=nums[i]*nums[i];
                k--;
                i++;
            }
            else
            {
                result[k]=nums[j]*nums[j];
                k--;
                j--;
            }
        }
        return result;
    }
};

2、长度最小的子数组(滑动窗口)

思路:这题最直白的想法就是用嵌套循环来求解,这样做的时间复杂度是O(n^2),如果能够用滑动窗口(实际上本质还是双指针,只不过代码执行的过程像是滑动窗口一样)来解决,就可以把时间复杂度降到O(n)。

KEY:首先要弄清for循环中的变量用来起什么作用,这点很重要,如果让他指向起始位置,那么另一个指针指向终止位置,通过遍历来不断求解,这又回到了嵌套循环的思路,但是如果让该变量指向终止位置,也就是说让终止位置往前遍历寻找长度最小的子数组,那么另一个指针就可以在终止位置找到满足条件的子数组时向滑动窗口一样往前滑动,从而缩小该子数组的范围,由于从头到尾两个指针只是分别遍历了一遍数组,因此时间复杂度为O(n)。

总结:双指针在解决数组类问题时,不管是对于有序数组还是无序数组,都是强大的。

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        //对于长度最小的子数组,可以通过滑动窗口来实现O(n)的时间复杂度
           int sublength=0;
           int i=0;//滑动窗口
           int j=0;//指向终止位置
           int result=INT32_MAX;
           int sum=0;
           for(;j<=nums.size()-1;j++)
           {
               sum+=nums[j];
               while(sum>=target)
               {
                   sublength=j-i+1;//例如:数组只有1个100,target=100
                   result=min(result,sublength);
                   sum-=nums[i];
                   i++;
               }
           }
            //如果result没有被赋值的话,返回0,否则返回result,用三目运算符来实现
               return result==INT32_MAX?0:result;
    }
};

3、螺旋矩阵(模拟)

思路:螺旋矩阵的本质就是绕圈计数,没有什么技巧,主要考察对于边界条件的处理

关键:对于边界条件,一定要坚持循环不变量原则,这里可以通过左闭右开或者左开右闭来实现,但关键是要坚持该原则,在对于每条边的处理中都保持一致即可。

小细节:
1.设置二维数组时要提前开辟内存,进行初始化,否则无法插入元素计数。
2.在循环结束后,如果边的长度是奇数,此时中间是一个点,要单独补上。

重要结论:循环不变量原则可以在边界类问题中(如二分法、螺旋矩阵)有效的解决边界条件的处理问题。

class Solution {
public:
    vector<vector<int>> generateMatrix(int n) {
        vector<vector<int>>matrix(n,vector<int>(n,0));
                 int startx=0;
                 int starty=0;
                 int count=1;
                 int loop=(n/2);
                 int offset=1;
                 int i,j;
                 while(loop--)
                 {
                     i=startx;
                     j=starty;
                     for(;j<n-offset;j++)
                     {
                         matrix[startx][j]=count++;
                     }
                     for(;i<n-offset;i++)
                     {
                         matrix[i][j]=count++;
                     }
                     for(;j>starty;j--)
                     {
                         matrix[i][j]=count++;
                     }
                     for(;i>startx;i--)
                     {
                         matrix[i][j]=count++;
                     }

                     startx++;
                     starty++;

                     offset++;                    
                 }

                 if(n%2==1)
                 {
                     int mid=n/2;
                     matrix[mid][mid]=count++;
                 }
        return matrix;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值