题目描述:
给定一个含有 n
个正整数的数组和一个正整数 target
。
找出该数组中满足其总和大于等于 target
的长度最小的 子数组
[numsl, numsl+1, ..., numsr-1, numsr]
,并返回其长度。如果不存在符合条件的子数组,返回 0
。
算法思路:
第一种暴力法,我认为也是双指针法(会超时)
「从前往后」枚举数组中的任意⼀个元素,把它当成起始位置。然后从这个「起始位置」开始,然 后寻找⼀段最短的区间,使得这段区间的和「⼤于等于」⽬标值。 将所有元素作为起始位置所得的结果中,找到「最⼩值」即可。
算法代码:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
int ret = Integer.MAX_VALUE; //ret初始化记录赋值最大值,方便最小的值都可以替换
for (int start = 0; start < n; start++) { //开始指针
int sum = 0; //记录本次指针总和sum的值
for (int end = start; end < n; end++) { //结束指针
sum += nums[end]; //每次都添加end指针的值
if (sum >= target) {
ret = Math.min(ret, end - start + 1); //每次结束判断最小值是本次吗
break;
}
}
}
return ret == Integer.MAX_VALUE ? 0 : ret; //如果结束的值还是和初始值一样就返回0.否则返回ret
}
}
第二种: 滑动窗口 O(N)
算法思路:
因为是连续的区间,可以使用滑动窗口来解决。
当窗口中的值满足判断条件,记录此时的值,然后和最小值比。具体思路当让滑动窗⼝满⾜:从 left 位置开始,窗⼝内所有元素的和⼩于 target (那么当窗⼝内元素之和 第⼀次⼤于等于⽬标值的时候,就是 left位置开始,满⾜条件的最⼩⻓度)。然后left可以右移动一位。
具体:当我们找到了一个满足条件的最小值,我们需要找到其他值,其实可以大胆的去掉现在的left,这样也可以避免大量的重复的计算。比如第一个left1到right1是满足条件的,更新结果以后left1右移一位,变成left2.此时有两种情况
第一种:left2-right1不满足
不满足的原因是left2小于left1,那么right1就要一直右移直到满足条件
第二种:left2-right1满足
满足的原因是left2大于left1,此时right1不用移动,更新此时的最小值,然后比较。 然后left2右移动一位,变成left3。
此时又有两种情况
第一种:left3-right1不满足
不满足的原因是left3小于left2,那么right1就要一直右移直到满足条件。
第二种:left3-right1满足
满足的原因是left3大于left2,此时right1不用移动,更新此时的最小值,然后比较。 然后left2右移动一位,变成left3。此时我们可以看到我们的最小值刚刚开始的[left1...right1],变成了[left3...right1],最小值和原来的比较小了2个。
算法代码:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n =nums.length,minSize = Integer.MAX_VALUE,sum = 0;//初始化值
for (int left = 0,right = 0; right < n; right++) {
sum += nums[right];//进窗口,不断的添加右指针
while (sum >= target){//判断,直到sum >= target的时候
minSize = Math.min(minSize,right-left+1); //更新结果
sum -= nums[left]; //出窗口
left++;//左指针右移动一位
}
}
return minSize == Integer.MAX_VALUE ? 0:minSize; //如果结束的值还是和初始值一样就返回0.否则返回ret
}
}
结果展示: