题目描述
给定一个含有 n 个正整数的数组和一个正整数 s ,找出该数组中满足其和 ≥ s 的长度最小的 连续 子数组,并返回其长度。如果不存在符合条件的子数组,返回 0。
示例:
输入:s = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
进阶:
如果你已经完成了 O(n) 时间复杂度的解法, 请尝试 O(n log n) 时间复杂度的解法。
思路分析
这里采用双指针+滑动窗口的方法。那么什么是滑动窗口呢?
如图,以 s = 7, nums = [2,3,1,2,4,3]
为例,要实现滑动窗口,得有两个指针,头指针start
指向子数组的第一个元素,尾指针end
指向子数组最后一个元素。
一开始时,start与end都指向子数组的第一个元素。
当end后移一位,我们就可以求得第一个元素和第二个元素的和。
通过end后移,我们可以累加求得子数组元素的和,当和大于等于给定输入阈值s时,end指针不再后移,就比如图中停止求和的条件就是 2+3+1+2 > 7
。此时我们还要判断这个子数组的长度是不是所有子数组长度中最小的那个,子数组长度可以通过指针的位置来求得,为end-start+1
。最后题目要求返回的子数组长度,就是滑动窗口的大小。
滑动窗口的关键在接下来的步骤中,当我们结束上面这次循环之后应该做什么? 我们可以将之前求得的子数组之和减去 start 指针位置上的元素值,然后将 start 指针后移,直到满足s<7 为止。窗口是不是就滑动了?
然后继续让end指针后移,循环往复,最后题目要求返回最小子数组长度,就是滑动窗口的最短长度。
示例代码
class Solution {
public int minSubArrayLen(int s, int[] nums) {
int n = nums.length;
if(n == 0){
return 0;
}
// end - start + 1 为子数组的元素个数
int start = 0;
int end = 0;
int sumVal = 0; // 子数组元素之和
int minLen = Integer.MAX_VALUE; //子数组的最小长度,初始化为Integer.MAX_VALUE
while(end < n){
sumVal += nums[end];
while(sumVal >= s){
minLen = Math.min(minLen, end - start + 1);
sumVal -= nums[start];
start++;
}
end++;
}
return minLen == Integer.MAX_VALUE ? 0 : minLen;
}
}
复杂度分析
- 时间复杂度:O(n)
- 空间复杂度:O(1)
来源:oschina
链接:https://my.oschina.net/u/4710178/blog/4679682