给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例 1:
输入:target = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例 2:
输入:target = 4, nums = [1,4,4]
输出:1
示例 3:
输入:target = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
提示:
1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
进阶:
如果你已经实现 O(n) 时间复杂度的解法, 请尝试设计一个 O(n log(n)) 时间复杂度的解法。
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/minimum-size-subarray-sum
方法一:利用双指针
1、定义两个指针i,j,其中i用于遍历数组,从而计算对应的子数组的和,j用于当和大于等于target的时候后移。此时两个指针的初始值都是0
2、定于一个变量sum,用于统计子数组的和。初始值为0
3、遍历数组,每遍历到一个数字,就将这个数字添加到sum中,然后判断sum是否大于等于了target,如果是,那么就将sum -= nums[ j ] ,然后 j 指针后移。但是我们需要统计子数组中长度最小的,所以在执行sum -= nums[ j ]之前,我们需要先获取 i - j + 1的最小值,将最小值赋值给res
4、遍历完毕之后,res就是我们想要的结果.
对应的代码:
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int i,sum = 0,j = 0;
int res = 0,min = Integer.MAX_VALUE;
for(i = 0; i < nums.length; i++){
/*
必须先写sum += nums[i],然后才写while循环,如果将这一步写在while
循环后面就会导致错误。为什么呢?因为如果将sum += nums[i]这一步写
在while循环后面,那么导致sum += nums[nums.length - 1]的时候,sum
有可能大于等于target,从而没有将所有的情况统计完毕,进而导致错
误。比如例子[2,3,1,2,4,3],target = 7的时候,那么根据代码进行调
试的时候就会发现,如果将sum += nums[i]写在while后面,就会错误,
原因就是上面说的,遍历到最后一个元素的时候,虽然sum +=
nums[nums.length - 1],但是少算了情况,导致结果的错误.
*/
sum += nums[i];
while(sum >= target){
/*
下面的代码可以写成这样:
res = Math.min(i - k + 1,res);
此时只要将res初始化为Integer.MAX_VALUE即可,但是
这样的话会有一中情况,就是最后返回res的时候我们需要
判断是否存在大于等于target的子数组,如果不存在,那么就
返回0,否则返回res,此时我们就需要通过判断res是否等于
Integer.MAX_VALUE来判断是否存在子数组,所以为了减少
判断这一步,就使用了下面的代码.
*/
res = Math.min(i - k + 1,min);
/*
这一步是必须的,如果不更新的话,那么min一直都是
Integer.MAX_VALUE,从而导致res的结果错误。
*/
min = res;
sum -= nums[k++];
}
}
/*
如果上面使用的是res = Math.min(i - k + 1,res)的话,那么这时候
res的初始值是Integer.MAX_VALUE,而不是0,同样的最后不是直接返回
res,而是判断res是否等于它的初始值,从而可以知道是否存在子数组
if(res != Integer.MAX_VALUE)
return res;
return 0;
*/
return res;
}
}
运行结果: