问题描述
Given an array of n positive integers and a positive integer s, find the minimal length of a contiguous subarray of which the sum ≥ s. If there isn’t one, return 0 instead.
Example:
Input: s = 7, nums = [2,3,1,2,4,3]
Output: 2
Explanation: the subarray [4,3] has the minimal length under the problem constraint.
问题分析
该问题是给定一个正整数组和一个目标整数s
,其目的是在数组中找到 元素之和 > s
的最短子数组,并返回它的长度。如果不存在 元素之和 > s
,则返回 0 。
- 暴力解法,直接两层循环找到所有的子数组,然后记录元素之和 > s 的最短数组。时间复杂度 O ( n 2 ) O(n^2) O(n2),样例会超时…
- 滑动窗口,需要找的是连续的子数组,而且当一个数组的和小于某一个值之后,则其子数组的和肯定小于该值,所以完成没必要对已经小于目标值的子数组再去缩减。
滑动窗口思想如下:
以数组[2, 3, 1, 2, 4, 3]
,s=7
为例。
滑动窗口[i, j]
初始为[0, 0]
即数组的第一个元素,滑动规则如下:
- 若元素之和 < s,窗口右边向右延伸,直到找到元素之和 > s 的子数组;第一次窗口为
[2,3,1,2]
,和大于7 - 若元素之和 > s,更新最小长度,
min=4
,并窗口左边向左移动,直到元素之和 < s。
该方法是找到每次刚好大于目标值的子数组,对那些必定小于目标值的子数组进行了剪枝。
解题代码
public static int minSubArrayLen(int s, int[] nums){
/**
* 暴力解法会超时,可以换一种思路:
* 使用双指针找大于 s 的区间,快指针用来求和,慢指针用来逼近找到最小的区间
* */
if (nums == null)
return 0;
int i = 0;
int j = 0;
int minLength = Integer.MAX_VALUE;
int sum = 0;
while (j < nums.length){
sum += nums[j++];
while (sum >= s){
minLength = Math.min(j-i, minLength);
sum -= nums[i++];
}
}
return minLength == Integer.MAX_VALUE ? 0 : minLength;
}