[Day 11]209.长度最小的子数组

今天我们来看一下这道力扣题目,难度中等
力扣链接:209.长度最小的子数组

题目描述:

给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。

示例:

输入:s = 7, nums = [2,3,1,2,4,3]

输出:2

解释:子数组 [4,3] 是该条件下的长度最小的子数组。

提示:

1 <= target <= 10^9

1 <= nums.length <= 10^5

这道题我用两种思路来解答,一种是暴力求解,一种是滑动窗口。

暴力求解

我们可以用两个for循环两个指针i,j来初始化起始位置和终止位置,用来遍历指针

不断寻找符合条件的最小数组长度

代码如下:

cpp 复制代码
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int sum=0;
        int result=INT32_MAX;//用来存储满足条件的最小数组长度
        int sublength=0;//定义一个子数组
        for(int i=0;i<nums.size();i++){//初始化i为起始位置
             sum=0;//
            for(int j=i;j<nums.size();j++){//初始化j为终止位置
               sum=sum+nums[j];//用来更新 前j个数的总和
              if(sum>=target){//如果sum>=target,说明找到了一个满足条件的区间
                sublength=j-i+1;//记录此时子数组的长度差,因为从零开始,所以+1
                result=result<sublength?result:sublength;//比较如果小于最小数组长度,返回自己,否则返回更新的子数组长度
                break;//我们找符合条件最短的子序列,所以一找到就退出条件
               }
               //如果sum<target就继续移动j
            }
        }//循环结束
        return result==INT32_MAX?0:result;//如果result没有被赋值,返回0,说明没有符合条件的子序列
    }
};

暴力求解的代码现在在力扣上已经超时了,大家看看就好。接下来的滑动窗口的思想是比较重要的。

滑动窗口

思路

上述暴力求解通过两个for循环遍历i,j,将所有符合条件的区间都列了出来,而滑动窗口用1个for循环遍历符合条件的区间。

滑动窗口类似于双指针法的一种,只不过这个过程类似于窗口,所以叫滑动窗口

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

那么问题来了,什么是窗口呢?初始位置,起始位置又是在哪里呢?

所谓窗口,就是在满足条件>=s的滑动时所形成的连续数组

因为只使用1个for循环,到底是初始化起始位置还是终止位置呢?我们假设初始化起始位置i,那么后面的终止位置要怎样遍历呢?就会又成为暴力求解了。

1.首先我们定义sum为总和,sublength为数组子长度,i为初始位置,都为0。定义result为最小数组子长度INT32_MAX。用来记录数组如果没有符合条件的情况。
2.接下来使用for循环来初始化终止位置为0,遍历这个数组。
3.将nums[j]逐个相加存到sum中。
4.然后判断条件当sum大于等于s时,那么更新sublength计算此时长度差,如果此时长度差大于最小数组长度差result时那么返回0,说明没有要找的,如果小于那么返回sublength。再用sum减掉nums[i]第一个元素后,i向前移动,j向后移动。(这步是滑动窗口的关键)
5.最后,当for循环结束了返回如果存在返回它的长度sublength,如果不存在符合条件的子数组,返回 0 。

完整代码

cpp 复制代码
class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int sum=0;//定义总和为0
        int sublength=0;//定义最小子数组为0
        int result=INT32_MAX;  //定义一个数为存储数组最小子长度
        int i=0;//定义初始位置i
        for(int j=0;j<nums.size();j++){//定义终止位置
            sum=sum+nums[j];//定义和为前j个数相加
            while(sum>=target){
                sublength=(j-i+1);//求出长度差,+1是因为从0开始
                result=result<sublength?result:sublength;//如果最小长度差<最小子长度就把长度差赋值成最小的
                sum=sum-nums[i];//用和减去第一个数,前移i,更新了区间数组,这步是滑动窗口的关键(不断变更)
                i++;//前移i
            }
        }
        return result==INT32_MAX?0:result;//如果结果等于原来的最小数组长度,那么就说明没找到,返回0,否则找到了新的满足条件的,就返回result
    }
};

总结

滑动窗口比暴力时间复杂度降低很多,因为暴力是所有结果都遍历一遍来找长度最小的,而滑动窗口通过子序列长度和大小,不断调节子序列的长度。本道题需要好好消化一下,稍微难了一点,希望我的思路能够帮助到你们呀~

相关推荐
大数据追光猿33 分钟前
Python应用算法之贪心算法理解和实践
大数据·开发语言·人工智能·python·深度学习·算法·贪心算法
Dream it possible!1 小时前
LeetCode 热题 100_在排序数组中查找元素的第一个和最后一个位置(65_34_中等_C++)(二分查找)(一次二分查找+挨个搜索;两次二分查找)
c++·算法·leetcode
夏末秋也凉1 小时前
力扣-回溯-46 全排列
数据结构·算法·leetcode
南宫生1 小时前
力扣每日一题【算法学习day.132】
java·学习·算法·leetcode
柠石榴1 小时前
【练习】【回溯No.1】力扣 77. 组合
c++·算法·leetcode·回溯
Leuanghing1 小时前
【Leetcode】11. 盛最多水的容器
python·算法·leetcode
qy发大财1 小时前
加油站(力扣134)
算法·leetcode·职场和发展
王老师青少年编程1 小时前
【GESP C++八级考试考点详细解读】
数据结构·c++·算法·gesp·csp·信奥赛
qy发大财1 小时前
柠檬水找零(力扣860)
算法·leetcode·职场和发展
瓦力的狗腿子1 小时前
Starlink卫星动力学系统仿真建模番外篇6-地球敏感器
算法·数学建模·simulink