模块二——滑动窗口:209.长度最小的子数组


一、题目解析

在这里插入图片描述
在这里插入图片描述
题目中提到了正整数的数组,这个需要注意一下,和我们接下来提到的单调性有关。我将以示例1来解析题目
在这里插入图片描述
这里我枚举了三个连续子数组,根据题目描述,我们需要返回sum>=target且长度最小的连续子数组的长度,即[4,3],len=2,而这题的答案也为2。

二、算法原理

解法一:暴力枚举

先用一个循环固定left,然后让right从left开始枚举所有连续子数组,接着循环遍历[left,right],求出sum,并且判断是否符合sum>=target,符合则用min更新,不符合则让right继续往右走。(这是最搓的方式,不用想肯定超时,时间复杂度为O(n^3)。
我们可以将其优化一下,在right边走的时候边用sum记录连续子数组的和,就可以少一层循环,然后在找到第一个连续子数组的时候更新记录,并且跳出循环,因为数组中都是正整数,继续加上下一个nums[right]只会>=target,且len会增加,我们求的是最小的len,所有无需继续枚举,直接跳到下一个left。(这就是单调性,时间复杂度为O(n^2)。

解法二:利用单调性+“同向双指针”(滑动窗口)优化

我们注意到本题中,left和right都往同一个方向移动,并且我们在暴力枚举的过程中right每次都要回退到left的位置,这边我们可以优化一下,在示例1中,[2,3,1,2]刚好符合第一个连续子数组且sum>=target,接下来我们只需让sum-=nums[left],left++即可
在这里插入图片描述
在这里插入图片描述

a.什么是滑动窗口?

这边就可以判断一次是否sum>=target,是则更新记录,否则right++,进入下一个判断,我们可以发现left和right现在都是同向的且不会回退的,这就是我们要讲滑动窗口的含义。

b.什么时候用滑动窗口?

答案就是我们一直再强调的单调性了。

c.怎么用滑动窗口?

在这里插入图片描述

这里要注意的是更新结果的位置每题都不完全一样,它有可能是在进窗口的时候就可以更新结果,而有的题是在判断结束之后,出窗口之前就更新结果,需要就题论题,而本题就是判断之后需要更新结果再出窗口。

d. 正确性

正如我在解法一中所说,利用了单调性,规避了很多没有必要的行为

e.时间复杂度

虽然我们的代码中使用了两个循环,但是我们看算法思想,left和right各遍历了一遍数组,也就是O(2n),即时间复杂度为O(n)。

三、代码实现

解法一:暴力枚举——O(n^2)

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int len = INT_MAX,n = nums.size();//用len记录结果
        for(int left = 0;left < n;left++)//开始位置
        {
            int sum = 0;//记录连续子数组的和
            for(int right = left;right < n;right++)//寻找结束位置
            {
                sum += nums[right];
                if(sum >= target)
                {
                    len = min(len,right - left + 1);//不断更新至最小值
                    break;
                }
            }
        }
        return len == INT_MAX ? 0 : len;
    }
};

解法二:滑动窗口——O(n)

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int sum = 0,len = INT_MAX,n = nums.size();//用len记录结果
        for(int left = 0,right = 0;right < n;right++)
        {
            sum += nums[right];//进窗口
            while(sum >= target)//判断
            {
                len = min(len,right - left + 1);//更新记录
                sum -= nums[left++];//出窗口
            }
        }
        return len == INT_MAX ? 0 : len;
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

全天

加油,大佬们!!!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值