首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >算法入门:专题二---滑动窗口(长度最小的子数组)类型题目攻克!

算法入门:专题二---滑动窗口(长度最小的子数组)类型题目攻克!

作者头像
胖咕噜的稞达鸭
发布2025-10-22 15:06:03
发布2025-10-22 15:06:03
2400
代码可运行
举报
文章被收录于专栏:C++初阶高阶C++初阶高阶
运行总次数:0
代码可运行

长度最小的子数组

长度最小的子数组

  1. 题目解析: 定义一个target目标值,在数组中要找到满足其总和大于等于target的长度最小的子数组,在示例1中,target是7,数组[ 2, 3 1 2 4 3 ],2+3+1+2=8,是连续子数组,而且满足>=7的条件,算一个;3+1+2+4>=7,也算,1+2+4=7,算一个;2+4+3>=7,也算;4+3=7,也算。在这些满足条件的数组中要找到长度最小的,已知是【4,3】,最终要返回最小数组的长度,是2,所以最后返回的是2。
  2. 算法原理:

解法一:

暴力枚举出所有的子数组的和。

暴力枚举策略优化:

题目中强调所有的数字都是正整数,当正整数相加的时候,加的数字越多总共和就会越大,涉及单调性!

先固定一个左区间,枚举右区间 具体做法如下:

[ 2, 3 1 2 4 3 ]给定一个数组,让left指向下标索引为0的位置,然后要定义一个sum用来存储子数组的和,接着还要定义一个right,这个right最开始指向的是下标索引为0的位置,当right向后进行遍历的时候,right指向索引为0的位置,sum=2;right++,sum=2+3=5;此时sum<target;继续遍历,right++,sum=2+3+1=6;此时sum<target;right++, sum=sum+nums[right]=2+3+1+2=8,此时sum=target,满足条件,由于题目中要求返回的是最小数组的长度,还要定义一个len,用来计算符合条件的数组的长度,此时len=4;当right++,继续走,sum=sum+nums[right]=8+4=12;又是一个满足条件的,len 此时为5. 此时right再次向后++,sum一定是满足大于target的条件,但是len是不断增加的,我们需要的是最小数组的长度,此时就可以停止枚举了。

然后这段区间的left就要更新一下了,left++,然后right需要回退到left的位置吗?

不需要,此时我们已经找到了前一个sum,也就是right在索引为3的位置,此时的sum=8,是第一个大于target的数组的和,right不用回退,我们只需要用第一个满足条件的sum长度减去num[left-1],然后接着判断此时的sum是否大于target,sum=sum(之前的)-num[left-1]=6,小于target,right++,sum=sum+num[right]=6+4=10,满足条件,大于target;len=4; 此时left++;继续进行枚举。

解法二:

利用单调性,使用同向双指针来优化。(同向双指针也就是滑动窗口)

  1. 什么是滑动窗口

本质上就是同向双指针,在遍历数组的时候会做到,就像一个窗口在数组中从左到右滑动。

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

在暴力解法的时候,两个指针都可以不回退,就可以用滑动窗口。

  1. 那么怎么用滑动窗口呢?

1.先初始化Left和right让他们来标记左区间和右区间。 2.进窗口 3.判断是否该出窗口,还要更新一下结果(这一步需要旧题论题)。

定义完left和的时候,就让right移动到一个符合条件的最佳位置。定义一个sum来维护窗口,sum增加的时候要判断是否大于target,是否满足条件,如果满足条件,此时需要更新一下结果,len 的长度要更新一下,让left向右移动一位数字,此时left已经出了窗口,然后sum=sum-num[left],len-1,再接着进行判断,此时的sum小于target,right++,一直进行四步操作。直到right指向为空。

  1. 怎么保证正确性? 利用了单调性,规避了很多没有必要的枚举行为,当sum第一次>=target的时候,right再次向后走,此时的sum一定是满足大于target的条件,但是len是不断增加的,我们需要的是最小数组的长度,此时就可以停止枚举了。
  2. 最终的时间复杂度是O(N)
  3. 将思路转换为代码!

题目中要求我们要最终返回最小子数组的长度,而且数组中加起来的和要大于或者等于target,所以先来定义一个sum,初始化为0,接着定义lenINT_MAX,也就是整型中的最大值,在后续更新的时候将len更新为每一次对应的符合要求的数组长度。

然后定义rightleft,用不回退的双指针滑动窗口来解决这个问题,首先,leftright的位置都指向索引为0的位置,其次,由于是right在不断向后移动,更新right,所以right<n,right++;

这里就进入了窗口,sum+=nums[right];接着进行判断是否此时的sum>=target,更新len的长度,不满足要求就一直让right加,直到sum>=target,此时len已经满足要求了,right如果不断++,此时会统计出来了所有left在索引为0,right移动小于n这段变化的区间里面满足sum>=target的值。但是由于right++时要判断,有没有继续往后走的必要性。当第一次满足了要求,再往后走就没有必要了。

len=min(len,right-left+1),取到这段区间中的len最小值。

然后要更新一下sum此时出窗口,left++,让sum-=nums[left],此时sum一定会小于target,不满足循环条件,跳出循环。再进行right++操作,如果目前的len小于之前的len就更新一下,否则不做改变,最后循环走完之后就会找到最小的len ,此时返回len,还要做一个判断,如果len此时的len找到最小的值了吗是否 符合sum>=taregt的规则,如果没有返回0,如果找到了就返回正确的len ,也就是我们更新出来的。return len==INT_MAX?0:len;

4. 上代码!

代码语言:javascript
代码运行次数:0
运行
复制
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int n=nums.size(),sum=0,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;
    }
};
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2025-10-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 长度最小的子数组
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档