Problem: 209. 长度最小的子数组
首先来分析一下本题的题目意思
target
,所以呢就返回了0但是要如何去寻找这个最小的子数组呢,我们马上来揭晓
我们通过分析此题的算法原理来看看该如何去进行求解
首先第一种,还是我们最熟悉的暴力解法
right
的不断后移中,我们发现了一组长度> target
的数据。但是呢我们这里使用的是【暴力枚举】,所以此时还会继续向后进行遍历操作→可以观察到,当这个right
继续后移将所遍历到的数加到sum
上去的时候,虽然sum
的大小是比target
来得大了,但是呢这个len
的长度也相对应地发生可增长,这个其实的话就不对了,因为题目中所要求我们的是求解 最小子数组的长度
看了上面的部分思路后,确实觉得暴力解法不可行,所以我接下去会使用【滑动窗口】的思想去做一个优化的操作
left
向后移动一位,此时子数组的和即为当前的sum
减去left
刚刚所指位置的那个数,即为【6】,那么我们在计算整个子数组的和时就可以不用让right
重新开始遍历计算对于上面的这种 “同向移动的指针” 我们就称之为【滑动窗口】,读者可以看看下面的这个动图
那接下去呢我就来叙述一下如何使用【滑动窗口】的思想
left = 0, right = 0
target
那有读者一定会问了,怎么能保证这个滑动窗口一定是正确的呢?
对于时间复杂度, 等会读者在看代码的时候可以看到是存在两个嵌套的循环,所以就自认为是 O ( n 2 ) O(n^2) O(n2),但是呢这里的时间复杂度应该是 O ( n ) O(n) O(n)才对
left
和right
指针在移动的时候都是一步步走的,当最后right
指针移动到末尾结束的时候,我们考虑最坏的情况,就是两个指针分别都遍历了一遍这个数组, 2 O ( n ) 2O(n) 2O(n)时间复杂度即为 O ( n ) O(n) O(n)没有开出任何多余的空间,那么空间复杂度即为 O ( n ) O(n) O(n)
以下即为滑动窗口的代码
len
是否有做更新,如果还是为最初的INT_MAX
的话就不对了class Solution {
public:
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size();
int sum = 0;
int len = INT_MAX;
for(int left = 0, right = 0; right < n; ++right)
{
sum += nums[right]; // 进窗口
while(sum >= target)
{
len = min(len, right - left + 1); // 更新最短长度
sum -= nums[left++]; // 出窗口
}
}
return len == INT_MAX ? 0 : len;
}
};