09. 长度最小的子数组
题目链接:
题目描述:

题目示例:

解法一:暴力枚举(易超时)
思路解析
从前往后枚举数组中的任意一个元素作为起始位置,然后从这个起始位置开始寻找一段最短的区间,使得这段区间的和大于等于目标值。将所有元素作为起始位置所得的结果中,找到最小值即可。
由于需要双重循环遍历所有可能的区间,时间复杂度较高,数据量大时容易超时,此处不再赘述代码。
解法二:滑动窗口
核心思路
此题分析的对象是一段连续的区间,非常适合使用滑动窗口的思想。
让滑动窗口满足:从 left 位置开始,窗口内所有元素的和小于 target。当窗口内元素之和第一次大于等于目标值的时候,就是 left 位置开始、满足条件的最小长度。
具体做法是将右端元素划入窗口之中,统计此时窗口内元素的和:
- 如果窗口内元素之和大于
target:更新结果,并且将左端元素划出去的同时继续判断是否满足条件并更新结果(因为左端元素可能很小,划出去之后依旧满足条件)。 - 如果窗口内元素之和不满足条件:
right++,让下一个元素进入窗口。
为什么滑动窗口更高效?
这个窗口寻找的是:以当前窗口最左侧元素(记为 left)为基准,符合条件的情况。也就是在这道题中,从 left 开始,满足区间和 sum >= target 时的最右侧(记为 right)能到哪里。
我们既然已经找到从 left 开始的最优区间,就可以大胆舍去 left。但如果像方法一一样,重新开始统计第二个元素(left + 1)往后的和,势必会有大量重复计算。因为在求第一段区间的时候,我们已经算出很多元素的和了,这些和是可以在计算下次区间和的时候直接复用的。
此时 right 的作用就体现出来了,我们只需要将 left 这个值从 sum 中剔除。从 right 这个元素开始,往后找满足 left + 1 元素的区间(此时 right 也有可能是满足的,因为 left 可能很小,sum 剔除掉 left 之后,依旧满足大于等于 target)。这样就能省掉大量重复的计算。
- 不仅解决了问题,效率也会大大提升。
时间复杂度: 虽然代码看起来是两层循环,但是我们的 指针和 指针都是不回退的,两者最多都往后移动 次。因此时间复杂度是 。







