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

题目链接: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.


思路:可以使用左右两个指针left,right,指出一个区间,其指针移动规则如下:

1. right指针--如果当前left和right区间的值小于s,则移动right指针,区间扩大1

2. left指针--如果当前left和right所指定的区间值大于s,则比较当前区间的长度是否是最小,并移动left指针,直到区间值小于s。

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

时间复杂度O(n)

代码如下:

class Solution {
public:
    int minSubArrayLen(int s, vector<int>& nums) {
        int len = nums.size(),sum =0, left = 0, right = 0, minLen = INT_MAX;
        while(right < len)
        {
            sum += nums[right++];
            while(left <= right && sum >= s)//当前区间值大于s,移动左指针
            {
                if(right - left < minLen)
                    minLen = right - left;
                sum -= nums[left++];
            }
        }
        if(minLen == INT_MAX) return 0;
        return minLen;
    }
};

还有一种时间复杂度为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


你可能感兴趣的:(LeetCode,算法,array,search,binary)