题目209: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.
More practice:
If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log n).
题目分析:
求和等于s的长度最小的子数组,子数组要求是连续的,子序列可以是不连续的,分别给出O(n)复杂度和O(nlogn)复杂度的两种解法。
1. 滑动窗口解法
思路分析:
滑动窗口,第一次看到有这样的解法,很巧妙,用两个指针left和right,分别指向滑动窗口的开始和结尾,如果滑动窗口中的和小于给定值,则滑动窗口的右边界向右滑,子数组和增加,直到滑动窗口内的子数组和>=给定值,比较最小长度和当前长度,然后滑动窗口左边界向右滑动。
那什么时候滑动结束呢?当滑动窗口的右边界right到达最右边,且滑动窗口内的子数组的和小于s时结束,不仅仅是滑动窗口右边界到达最右边就结束,因为此时左边界可能还可以滑动。
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int res, fast, slow, len, sum;
len = nums.size();
if (len == 0)
return 0;
fast = 0;
slow = 0;
/*
* res最大值是len+1,而不是len,因为如果是len,不能判断
* 是否是没找到,因为还可以是数组所以内容和==s的情况
*/
res = len + 1;
sum = nums[0];
while (fast < len) {
while (sum < s && fast < len)
sum += nums[++ fast];
if (sum >= s) {
res = min(res, fast - slow + 1);
sum -= nums[slow ++];
}
}
return res == len + 1 ? 0 : res;
}
};
2. 预处理数组解法
思路分析:
采用预处理数组的解法,建立sum[len + 1]数组,sum[i]表示nums[1…i - 1]子数组的和,也就是下标i之前数组的和,然后对应每一个sum[i],用二分查找法找到子数组的右边界,使该子数组的和大于sum[i] + s,然后更新最小长度。很巧妙的解法。
class Solution {
public:
int minSubArrayLen(int s, vector<int>& nums) {
int len = nums.size();
if (len == 0)
return 0;
vector<int> sum(len + 1);
int i, res;
sum[0] = 0;
res = len + 1;
for (i = 1; i < len + 1; i ++)
sum[i] = sum[i - 1] + nums[i - 1];
for (i = 0;i < len + 1; i ++) {
/* 参数是sum数组中的下标 */
int right = BinarySearch(sum, i + 1, len, sum[i] + s);
if (right == len + 1)
break;
if (res > right - i)
res = right - i;
}
return res == len + 1 ? 0 : res;
}
int BinarySearch(vector<int> sum, int left, int right, int key) {
while (left <= right) {
int mid = (left + right) / 2;
if (sum[mid] >= key)
right = mid - 1;
else
left = mid + 1;
}
return left;
}
};