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.
If you have figured out the O(n) solution, try coding another solution of which the time complexity is O(n log n).
这个问题跟前面的最小窗口子串问题是类似。这里会介绍时间复杂度分别为 O ( n ) 和 O (n log n )的2种解法。
有2个指针,start, end 表示子串的开始和结束。
1. 从start index = 0 开始,先找到和满足要求的子串。
2. start++看看有没有更小的子串。
最小对求得的更小子串求min,得到最终的最小子串了。
这个算法的时间复杂度为 O ( n )。
运行时间:
代码:
public int minSubArrayLen(int s, int[] nums) {
int start = 0, end = 0, n = nums.length, curSum = 0, minLen = Integer.MAX_VALUE;
while (end < n) {
//find the valid window
while (end < n && curSum < s) {
curSum += nums[end++];
}
if (curSum < s) {
break;
}
//try to find a smaller window
while (start < end && curSum >= s) {
curSum -= nums[start++];
}
if (end - start + 1 < minLen) {
minLen = end - start + 1;
}
}
return minLen == Integer.MAX_VALUE ? 0 : minLen;
}
O (n log n)的解法参考于:
以:nums : [ 2 3 1 2 4 3], 求 s = 7为例。
我新创建一个累计和的数组 sums 为[ 0 2 5 6 8 12 15]。sums[ i ] 表示nums 中 index < i 的所有值的和。
对于nums, index = i 的时候,我想要找到跟 i 间隔值为s的下标。即在新数组中 >= sums[ i ] + s 值的下标。因为新数组是有序的,所以可以通过二分查找进行搜索。每次搜索的时间复杂度度为logN, 所有总的时间复杂度为O ( N log N )。
代码:
private int binarySearch(int lo, int hi, int key, int[] sums) {
while (lo <= hi) {
int mid = (lo + hi) / 2;
if (sums[mid] >= key) {
hi = mid - 1;
} else {
lo = mid + 1;
}
}
return lo;
}
public int solveNlogN(int s, int[] nums) {
int[] sums = new int[nums.length + 1];
for (int i = 1; i <= nums.length; i++) {
sums[i] = sums[i - 1] + nums[i - 1];
}
int minLen = Integer.MAX_VALUE;
for (int i = 0; i < sums.length; i++) {
int end = binarySearch(i + 1, sums.length - 1, sums[i] + s, sums);
if (end == sums.length) {
break;
}
if (end - i < minLen) {
minLen = end - i;
}
}
return minLen == Integer.MAX_VALUE ? 0 : minLen;
}