1.题目描述
给定一个含有 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 = 11, nums = [1,1,1,1,1,1,1,1]
输出:0
来源:力扣(LeetCode)
2.题目分析
2.1 暴力解法
因为数组全为正整数,所以可以得出在固定起始端点的时候子数组越长得到的子数组和就越大。因而我们就很容易可以想到时间复杂度为O(N2)的暴力解法。具体来说就是每次确定子数组起始点为i
后,从i
开始逐步遍历(一步一步增长子数组长度),直到nums[i]+...nums[j]>=target
时退出本轮循环,此时的j-i+1
就是此次的子数组长度。
具体代码见第3.1部分。
2.2 双指针法
一般数组之类的问题都可以考虑使用双指针法来解决,本题也一样。我们回到问题本身是求一个子数组,其实也就是求一个满足区间内所有的数的和大于等于target
的子区间[i,j]
。这样的话我们就可以以i和j
作为两个指针分别指向子数组头尾来进行操作。
这种方法的基本思想是与暴力求解法类似,从数组维护一个子区间[i,j]
。不同的是此时我们只有一次循环,也就是说只根据一个指针来进行循环,具体是每当区间的和大于target时,我们就移动i指针但是j指针在其原本位置不变,不用再像穷举一样回到i指针后面。下面是其求解步骤:
- 首先初始化
i
指针指向数组首部,确定参数res
记录最短长度,sum
记录子数组和 - 声明指针
j
从头至尾循环数组,sublength
记录子数组长度 - 每当当前区间内元素和大于
target
,就更新sublength
(j-i+1
),并决定是否更新res
(检查是否更短),再将sum
子数组和进行更新(此时i元素被排除)
3.题目解答
1)暴力解法
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size();
int sublength = n;
int result = n+1;
for(int i=0;i<n;i++){
int sums = 0;
for(int j=i;j<n;j++){
sums+=nums[j];
if(sums>=target){
sublength = j-i+1;
result = result<sublength?result:sublength;
break;
}
}
}
return result==n+1?0:result;
}
};
2)双指针法——滑动窗口
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size();
int sublength = n;
int result = n+1;
int sum = 0;
int i=0;
for(int j=0;j<n;j++){
sum+=nums[j];
//华东窗口的移动,在这里只移动左端,因为右端做循环操作
while(sum>=target){
sublength = j-i+1;
result = result<sublength?result:sublength;
sum -= nums[i++];
}
}
return result==n+1?0:result;
}
};
总结:本体也可以用前缀数组(参考560题)的方式来解决