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