注:
题目:
给定一个含有 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)) 时间复杂度的解法。
题解:
解题思路
连着做了好几道滑动窗口的题目,实现滑动窗口的框架是定死的,用left,right来刻画窗口,窗口区间为[left, right),注意为半开半闭。框架如下:
void slidwindow(vector<int> nums)
{
int left = 0, right = 0;
while(right < nums.size())
{
...//扩大右边界并更新窗口状态
right++;
while(需要收缩)//窗口到达什么状态需要收缩
{
...//缩小左边界并更新窗口状态
left++;
}
}
}
滑动窗口重点在于:
显然对于这道题,我们需要关注的窗口状态就是窗口内所有数的和,那么如何刻画窗口状态呢?我们设置了一个变量sum,显然这个变量需要在窗口边界发生改变时不断更新,框架注释已经给出。
那么窗口到达什么状态需要收缩呢?即内部while循环的条件,显然当窗口内部所有数字的和>=target我们就收缩来寻找更小的满足条件的窗口。这样一来代码就很好写了。
复杂度分析
时间复杂度:O(n),其中 n 是数组的长度。指针 start 和 end 最多各移动 n 次。
间复杂度:O(1)。
class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int start=0;
int end=0;
int sum=0;
int lens=INT_MAX;
int size=nums.size();
while(end<size){
sum+=nums[end];
end++;
while(sum>=target){
lens=min(lens,end-start);
sum-=nums[start];
start++;
}
}
return lens==INT_MAX?0:lens;
}
};