【算法】滑动窗口破解长度最小子数组

在这里插入图片描述

Problem: 209. 长度最小的子数组

题意分析

首先来分析一下本题的题目意思

  • 题目中会给到一个数组,我们的目的是找出在这个数组中 长度最小的【连续】子数组,而且要返回这个子数组的长度

1.jpg

  • 那我们首先来看示例1,在所找出的所有连续的子数组后,我们需要去比较谁的长度比较短一些,然后去选择短一些的这个子数组

2.jpg

  • 下面们我们看这个示例3,其最后的返回长度为0,原因就在于给出的整型数组中所有数之和还是没有超过target,所以呢就返回了0

3.jpg

💬 但是要如何去寻找这个最小的子数组呢,我们马上来揭晓🖐

算法原理讲解

我们通过分析此题的算法原理来看看该如何去进行求解

暴力枚举O(N^2)

首先第一种,还是我们最熟悉的暴力解法

  • 不过也是要使用到双指针的,我们从0的位置开始向后遍历

4.jpg

5.jpg

6.jpg

7.jpg

  • 好,通过上面的这个图示,我们可以清晰地看出经过right的不断后移中,我们发现了一组长度> target的数据。但是呢我们这里使用的是【暴力枚举】,所以此时还会继续向后进行遍历操作→

可以观察到,当这个right继续后移将所遍历到的数加到sum上去的时候,虽然sum的大小是比target来得大了,但是呢这个len 的长度也相对应地发生可增长,这个其实的话就不对了,因为题目中所要求我们的是求解 最小子数组的长度

8.jpg

利用单调性,滑动窗口求解

看了上面的部分思路后,确实觉得暴力解法不可行,所以我接下去会使用【滑动窗口】的思想去做一个优化的操作

  • 我们可以将left向后移动一位,此时子数组的和即为当前的sum减去left刚刚所指位置的那个数,即为【6】,那么我们在计算整个子数组的和时就可以不用让right重新开始遍历计算

9.jpg

💬 对于上面的这种 “同向移动的指针” 我们就称之为【滑动窗口】,读者可以看看下面的这个动图

滑动窗口演示.gif

那接下去呢我就来叙述一下如何使用【滑动窗口】的思想

  1. left = 0, right = 0
  2. 数据进窗口
  3. 判断当前数据是否超过了目标值target
    1. 更新结果,数据出窗口
  4. 继续循环往复
  • 读者可以通过看下面的算法流程图,让后配合后面的代码,来思考这个滑动窗口的奇妙之处

10.jpg

💬 那有读者一定会问了,怎么能保证这个滑动窗口一定是正确的呢?

  • 虽然在这里我们并没有像暴力枚举那样列出的可能性然后再去比较,但是呢我们可以知道接下来的情况枚举了也是白枚举,所以呢我们利用【单调性】,规避了很多没有必要的枚举行为

复杂度

  • 时间复杂度:

对于时间复杂度, 等会读者在看代码的时候可以看到是存在两个嵌套的循环,所以就自认为是 O ( n 2 ) O(n^2) O(n2),但是呢这里的时间复杂度应该是 O ( n ) O(n) O(n)才对

  • 我们通过看下面的这张图来理解一下,leftright指针在移动的时候都是一步步走的,当最后right指针移动到末尾结束的时候,我们考虑最坏的情况,就是两个指针分别都遍历了一遍这个数组, 2 O ( n ) 2O(n) 2O(n)时间复杂度即为 O ( n ) O(n) O(n)

11.jpg

  • 空间复杂度:

没有开出任何多余的空间,那么空间复杂度即为 O ( n ) O(n) O(n)

Code

以下即为滑动窗口的代码

  • 注意最后在返回的时候要判断这个len是否有做更新,如果还是为最初的INT_MAX的话就不对了
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n = nums.size();
        int sum = 0;
        int len = INT_MAX;
        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;
    }
};

在这里插入图片描述

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 20
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

烽起黎明

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值