[LeetCode]day 5 209.长度最小的子数组

题目描述

给定一个含有 n 个正整数的数组和一个正整数 target 。

找出该数组中满足其总和大于等于 target 的长度最小的 

子数组

 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度如果不存在符合条件的子数组,返回 0 。

示例 1:

输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。

示例 2:

输入:target = 4, nums = [1,4,4]
输出:1

示例 3:

输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0j

解题

一.暴力枚举

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int min = INT_MAX, l = 0; //用min来储存最小值
        for (int i = 0; i < nums.size(); i++) {
            int sum = 0;
            l = 0;
            for (int j = i; j < nums.size()&& sum < target; j++) {
                sum += nums[j];
                l++; 
            } 
            if ( sum>=target &&l < min) {
                min = l;
            }
        }
        if (min !=INT_MAX) {
            return min;
            }
        else {
            return 0;
        }
    }
};

最容易想到的就是暴力枚举,通过双重for循环把所有区间都枚举出来 

注意将min初始化int_max的手法

但是这种方法做会超过时间限制


二.滑动窗口

class Solution {
public:
    int minSubArrayLen(int target, vector<int>& nums) {
        int sum=0,subLen=0,re=INT_MAX,i=0;
       for(int j=0;j<nums.size();j++){
          sum+=nums[j];
          while(sum>=target){
             subLen=j-i+1;
             re=min(re,subLen);
             //移动起始位置
             sum-=nums[i];
             i++;
          }
       }
       return (re==INT_MAX)?0:re;
    }
    
};

我们想用一个for循环来做两个for循环的事,如果用j来充当符合条件的子集合的起点,其实和暴力枚举没有区别;

所以我们用j来充当子集合的终点。当下标从0~j的集合元素加起来大于target时,我们就得到了一个符合总和大于target条件的集合,此时就需要移动集合的起点,看看能不能缩小这个集合的长度。

例如 target=7; nums={1,2,3,4} 当j=3时,sum>7,此时将起点向后移1位,即从2开始,sum=9符合条件,起点可以再向后移一位 sum=7依旧符合条件 将起点再向后移一位,sum=4就不符合条件了 所以最小长度为2!

这个元素的时间复杂度为O(n) 

为什么呢?明明for循环内部还用了一个while循环 

因为i的增加是不可逆的!

当j从左向右遍历数组时,j增加,i只能向右增加 i最多只访问每一个元素1次,j也最多访问每个元素一次 此时整个数组的访问次数最多为2n次

为什么说i的增加是不可逆的?

例如:num={2,3,4,7} target=7;

当j=2时,target=9; 此时移动起点 target=7,满足条件 再往前移动起点 target<7 不满足 此时subLen=2,i=1,sum=7;

继续外层for循环 target=14满足条件 此时移动起点肯定不用从0再开始了! 符合条件的集合的起点要么是我们刚刚找到的那个,要么是更靠后的,所以只需要将i继续++得到i=2 此时sum=11;符合条件 起点继续向前移动i=3  sum=7;   所以最后可以确定最小长度为1!

相比于暴力搜索,这种方法到底节省了哪些部分?

如果按暴力搜索的方法来思考,对于每一个j,i 都要从0~j遍历一遍 

而对于滑动窗口法,省略了i过大的部分 如果有一个i已经不满足条件了,就不会继续增加i;

省略了i过小的部分,因为如我前面解释的那样,i的增加是不可逆的,只会向前。


报复性休息了一天多。。希望米娜桑督促我每天都更新,,

最后,祝大家除夕快乐呀

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

因兹菜

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

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

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

打赏作者

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

抵扣说明:

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

余额充值