209. 长度最小的子数组
给定一个含有 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
这道题一开始我是想着找出数组中最大的那个值,然后从那个值开始加起,加到大于等于target就退出,并返回长度值。否则返回0。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int len=nums.size();
int max=0; //找出数组中小于等于target并且是最大的那个值
int k=0; //max的下标
int i;
int sum=0;
int g=0; //最小长度
for(i=0;i<len;i++){
if(nums[i]>max&&nums[i]<=target){
max=nums[i];
k=i;
}
}
for(int j=k;j<len;j++){
if(sum>=target){
break;
}
sum+=nums[j];
g++;
}
if(sum<target){
return 0;
}
return g;
}
};
运行后结果是这样的,只通过了10个测试点,当遇到如[1,2,3,4,5]的情况时,输出的是0,因为最大值在最后一个元素。所以我这种方法不可行,后来去查找资料,发现了一篇讲得很好的文章。
Carl哥的推文(代码随想录)
里面讲的是两种方法。
第一种是暴力的方法:
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int sum=0;
int result=INT32_MAX; //把最终结果设为最大值,主要是为了最后return的时候做判断
int z=0; //每个子字符串的长度
for(int i=0;i<nums.size();i++){
sum=0;
for(int j=i;j<nums.size();j++){
sum+=nums[j];
if(sum>=target){
z=j-i+1;
result=result<z ? result :z;
break;
}
}
}
return result==INT32_MAX ? 0:result; //要是没有一个符合条件的子串,则返回0
}
};
时间复杂度为O(n^2)
第二种是滑动窗口
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int result=INT32_MAX;
int zi=0;
int i=0; //可以理解为头指针
int sum=0;
for(int j=0;j<nums.size();j++){
sum+=nums[j];
while(sum>=target){ //while语句是滑动窗口的精髓,同时也是降低时间复杂度的原因。
zi=(j-i)+1;
result = result<zi ? result : zi;
sum-=nums[i++]; //移动头指针
}
}
return result<zi?result:zi;
}
};
时间复杂度为O(n)。操作数在进入for语句后被操作一次,在where语句被操作一次,所以为O(2*n),也就是O(n).