题目
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.
算法
O(N)
滑动窗口的形式
双指针
http://www.cnblogs.com/grandyang/p/4501934.html
这道题给定了我们一个数字,让我们求子数组之和大于等于给定值的最小长度,跟之前那道 Maximum Subarray 最大子数组有些类似,并且题目中要求我们实现O(n)和O(nlgn)两种解法,那么我们先来看O(n)的解法,我们需要定义两个指针left和right,分别记录子数组的左右的边界位置,然后我们让right向右移,直到子数组和大于等于给定值或者right达到数组末尾,此时我们更新最短距离,并且将left像右移一位,然后再sum中减去移去的值,然后重复上面的步骤,直到right到达末尾,且left到达临界位置,即要么到达边界,要么再往右移动,和就会小于给定值。代码如下
// O(n)
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
if (nums.empty()) return ;
int left = , right = , sum = , len = nums.size(), res = len + ;
while (right < len) {
while (sum < s && right < len) {
sum += nums[right++];
}
while (sum >= s) {
res = min(res, right - left);
sum -= nums[left++];
}
}
return res == len + ? : res;
}
};
算法
二分钟查找
O(NlgN)
下面我们再来看看O(nlgn)的解法,这个解法要用到二分查找法,思路是,我们建立一个比原数组长一位的sums数组,其中sums[i]表示nums数组中[0, i - 1]的和,然后我们对于sums中每一个值sums[i],用二分查找法找到子数组的右边界位置,使该子数组之和大于sums[i] + s,然后我们更新最短长度的距离即可。代码如下:
// O(nlgn)
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int len = nums.size(), sums[len + ] = {}, res = len + ;
for (int i = ; i < len + ; ++i) sums[i] = sums[i - ] + nums[i - ];
for (int i = ; i < len + ; ++i) {
int right = searchRight(i + , len, sums[i] + s, sums);
if (right == len + ) break;
if (res > right - i) res = right - i;
}
return res == len + ? : res;
}
int searchRight(int left, int right, int key, int sums[]) {
while (left <= right) {
int mid = (left + right) / ;
if (sums[mid] >= key) right = mid - ;
else left = mid + ;
}
return left;
}
};