长度最小的子数组--滑动窗口

在这里插入图片描述

暴力法

两个for循环,然后不断的寻找符合条件的子序列,时间复杂度很明显是O(n^2) 。

时间复杂度:O(n^2)
空间复杂度:O(1)
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
       int result=INT32_MAX;//最终结果。要返回长度最小长度,起始设置为最大,等待更新
       int sum;   //用来计算子序列的数值之和
       int sublen;//用来记录子序列的长度
       
       int size=nums.size();
       for(int ii=0;ii<size;ii++){// 设置子序列起点为ii
          sum=0;
          for(int jj=ii;jj<size;jj++){ // 设置子序列终止位置为jj
             sum+=nums[jj];
             if(sum>=target){// 一旦发现子序列和超过了target,更新result
                 sublen=jj-ii+1;// 计算子序列的长度
                 result=result<sublen ? result:sublen;
                 break;// 因为我们是找符合条件最短的子序列,所以一旦符合条件就break
             }
          }
       }
       // 如果result没有被赋值的话,就返回0,说明没有符合条件的子序列
       return result==INT32_MAX? 0:result;
    }
};

滑动窗口

所谓滑动窗口,「就是不断的调节子序列的起始位置和终止位置,从而得出我们要想的结果」。

在这里插入图片描述

其实从动画中可以发现滑动窗口也可以理解为双指针法的一种!只不过这种解法更像是一个窗口的移动,所以叫做滑动窗口更适合一些。

在本题中实现滑动窗口,主要确定如下三点:

窗口内是什么?
如何移动窗口的起始位置?
如何移动窗口的结束位置?

窗口就是 满足其和 ≥ s 的长度最小的 连续 子数组。

窗口的起始位置如何移动:如果当前窗口的值大于s了,窗口就要向前移动了(也就是该缩小了)。

窗口的结束位置如何移动:窗口的结束位置就是遍历数组的指针,窗口的起始位置设置为数组的起始位置就可以了。

解题的关键在于 窗口的起始位置如何移动,如图所示:
在这里插入图片描述
可以发现「滑动窗口的精妙之处在于根据当前子序列和大小的情况,不断调节子序列的起始位置。从而将O(n^2)的暴力解法降为O(n)。

class Solution{
public:
    int minSubArrayLen(int target,vector<int>& nums){
        int result=INT32_MAX;
        int sum=0;   // 滑动窗口数值之和
        int sublen=0;// 滑动窗口的长度
        int ileft=0;//滑动窗口起始位置

        int size=nums.size();
        //滑动窗口结束位置其实就是遍历数组的指针
        for(int iright=0;iright<size;iright++){
            sum+=nums[iright];
            while(sum>=target){
              sublen=iright-ileft+1;
              result=result<sublen? result:sublen;
              //双指针暴力解法中是跳出第二层循环到第一层循环刷新sum=0,然后移动子序列起点,在进入第二层循环重新计算sum
              //此处滑动窗口,直接改变滑动窗口起始位置,不必将sum归零重新计算,只是把起始位置值删去即可
              sum-=nums[ileft++];// 这里体现出滑动窗口的精髓之处,不断变更i(子序列的起始位置)
            }
        } 
        return result==INT32_MAX? 0:result;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值