[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
    }
};

总结

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

相关推荐
HUT_Tyne26527 分钟前
力扣--494.目标和
数据结构·算法·leetcode
xianwu54331 分钟前
cpp编译链接等
linux·开发语言·网络·c++·git
ADwwC1 小时前
已知n找最小正整数x使n*x为一个平方数
算法
graceyun2 小时前
牛客网刷题 ——C语言初阶(5操作符)——BC90 矩阵计算
c语言·算法·矩阵
莹雨潇潇3 小时前
约瑟夫问题
数据结构·c++·算法
Mr.kanglong3 小时前
【递归、搜索与回溯】二叉树的深搜
数据结构
花仙子1663 小时前
C#运动控制系统:雷赛控制卡实用完整例子 C#雷赛开发快速入门 C#雷赛运动控制系统实战例子 C#快速开发雷赛控制卡
开发语言·算法·c#
怀念无所不能的你3 小时前
洛谷P5318 【深基18.例3】查找文献(c嘎嘎)
算法
AmosCloud20133 小时前
3.5 字典树(Trie)与后缀树
开发语言·数据结构·链表·c#
Fishel-3 小时前
预测facebook签到位置
人工智能·python·算法·机器学习·近邻算法·facebook