[leetcode] 209. Minimum Size Subarray Sum 解题报告

63 篇文章 0 订阅
16 篇文章 0 订阅

题目链接:https://leetcode.com/problems/minimum-size-subarray-sum/

Given an array of n positive integers and a positive integer s, find the minimal length of a 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.

click to show more practice.


思路:可以使用维护一个区间,使得区间在这个区间里的和是小于s的,如果加上一个数之后区间和大于s了,那么就从区间左边开始删元素,并且边删边判断是不是和依然大于s,更新结果.

思路大概就是这样。刚开始理解错了题意,以为就是找最短加起来大于s的数的个数,然后排了个序,提交WA才意识到错了。anyway,move on!

时间复杂度O(n)

代码如下:

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        if(nums.size() == 0) return 0;
        int Min = INT_MAX, left = 0, cnt = 0, len = nums.size();
        for(int i = 0; i< nums.size(); i++)
        {
            cnt += nums[i];
            while(cnt >= s)
            {
                Min = min(Min, i-left+1);
                cnt -= nums[left++];
            }
        }
        return Min==INT_MAX?0:Min;
    }
};


还有一种时间复杂度为O(n*log(n))的二分查找的算法。这种算法的思想是用一个数组sums[i]来保存前i-1个数的和。这样可以保持数组的递增,然后从一个位置用二分查找大于sums[i] + s的值。之所以用sums[i] + s作为key来查找是因为这样就可以抛弃掉前i-1位数的和,查找一个从i开始的和大于s的区间。

举个栗子:[2,3,1,2,4,3], 7

我们可以计算得出sums[] = {0, 2, 5, 6, 8, 12, 15}

要怎么查找一个大于等于s的区间呢?

1. 首先我们从sums的位置1开始(即值为2的位置),查找在sums中值大于sums[0] + s(即7)的位置,可以得出是在位置4,即本次查找到的区间长度是4

2. 第二次我们从sums中位置2(sums中值为5的位置)开始,查找值大于sums[1] + s(即9)的位置(这样其实是抛弃了2的值)。得出位置在5,区间长度还是4.

3. 这次从sums中位置3开始,查找值大于sums[2]+s(即12)的位置(抛弃了2 和3的和)得出位置在5,区间长度为3,

4. 重复上次的操作,这次可以得出区间长度为2

这就是二分查找的思想。

代码如下:

class Solution {
public:
    int binarySearch(int left, int right, int sums[], int key)//二分查找大于sums[i]+s的位置
    {
        while(left <= right)
        {
            int mid = (left+right)/2;
            if(sums[mid] < key) 
                left = mid + 1;
            else 
                right = mid - 1;
        }
        return left;
    }
    int minSubArrayLen(int s, vector<int>& nums) {
        
        int len = nums.size(), sums[len+1] = {0}, minLen = INT_MAX;
        for(int i = 1; i<= len; i++)
            sums[i] = sums[i-1] + nums[i-1];
        for(int i = 0; i < len; i++)
        {
            //找到从i+1位置开始的大于s的区间右边界
            int pos = binarySearch(i+1, len, sums, sums[i]+s);
            if(pos == len+1) continue;//如果没有找到这个边界,则不更新长度
            minLen = min(minLen, pos - i);//更新长度
        }
        return minLen==INT_MAX?0:minLen;
    }
};
第二种方法参照:http://www.cnblogs.com/grandyang/p/4501934.html


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值