LeetCode 209. Minimum Size Subarray Sum 滑动窗口

一、题目

Given an array of n positive integers and a positive integer s, find the minimal length of a contiguous subarray of which the sum ≥s. If there isn't one, return 0 instead.

For example, given the array [2,3,1,2,4,3] and s = 7,
the subarray [4,3] has the minimal length under the problem constraint.

题意:提供一个有n个数的正整数的数组和一个正整数s,在数组中查找连续最小子数组使得其和大于等于s,返回最小连续子数组的长度

注意:1.首先注意是连续的子数组,两重含义:是原数组的子区间并且是连续的子区间。

        2.返回的是子数组的长度,所以存在唯一解。当返回的是连续子数组可能会有无穷多解,注意询问清楚

        3.当存在无解的情况返回0

思路:首先设定滑动窗口大小[l...r],当滑动窗口内元素和sum小于s扩大右侧加载一个元素,并再次判断是否大于s,若小于s继续向右加载,若大于s比较更新最短子数组的长度,并在下次循环中减少左侧元素使得窗口能够向右动态滑动。整个过程中滑动窗口的长度是不固定的。

时间复杂度:O(n)
空间复杂度:O(1)

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int l=0,r=-1;   //表示滑动窗口的大小[l...r]初始化为无效的
        int sum = 0;
        int res = nums.size()+1;     //记录满足条件的窗口长度,因为是找最小长度,初始值应该是比数组长度大
        while(l<nums.size()/*这个条件能自动过滤nums为空的情况*/)
        {
            if((r+1 < nums.size())/*当有[]操作一定要预防数组越界*/&&sum<s)           //当不满足时,滑动窗口向右扩展一位
            {
                r++;
                sum+=nums[r];
            }
            else
            {
                sum-=nums[l];
                l++;
            }
            
            if(sum >= s)             //无论向右加载元素还是向左删除删除元素,都需要再次判断是否满足条件比较更新最短的连续子数组长度
            {
                res=min(res,r-l+1);  //r-l+1因为滑动窗口是左右闭区间[l,r]所以需要+1    
            }
        }
        if(res == nums.size()+1)
        {
            return 0;
        }
        return res;
    }
};




当然以上解法如果一时想不到,可以尝试暴力解法,这种解法尽管在leetcode上超时,但是其中部分思想还是可以借鉴的。

预处理:定义了一个vector<int> sums; 这个sums[i]存放的就是[0...i-1]的和,那么求出连续的子区间的和是可以很方便的

            [l...r]内元素和等于sums[r+1]-sums[l]。

外围循环遍历所有元素,内层循环就是从l当前元素到最后的元素。

思路就是:挨个查找当前元素和之后的元素间的和是否满足

时间复杂度:O(n^2)
空间复杂度:O(n)
class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        // sums[i]存放nums[0...i-1]的和
        vector<int> sums(nums.size()+1,0);
        for( int i = 1 ; i <= nums.size() ; i ++ )
            sums[i] = sums[i-1] + nums[i-1];

        int res = nums.size() + 1;
        for( int l = 0 ; l < nums.size() ; l ++ )
            for( int r = l ; r < nums.size() ; r ++ ){
                // 使用sums[r+1] - sums[l] 快速获得nums[l...r]的和
                if( sums[r+1] - sums[l] >= s )
                    res = min( res , r - l + 1 );
            }

        if( res == nums.size() + 1 )
            return 0;

        return res;
    }
};


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值