题目描述
正整数数组中,求和 ≥ target 的最短连续子数组长度(没有返回 0)。
nums = [2, 3, 1, 2, 4, 3]
target = 7
输出 = 2 (子数组 [4,3])
思路解析
枚举每个起点终点再求和,n² 甚至 n³。换个思路:用一个窗口,右边扩进新数、和够了就从左边缩,全程只扫一遍。
r 不断右移把数加进窗口;一旦窗口和 ≥ target,就记录长度,并尽量把 l 右移缩短窗口(同时减去左端值),直到和不够再继续扩。
r 扩到 3:r 一路扩到下标 3,窗口 [2,3,1,2] 和 = 8 ≥ 7。记下长度 4,开始缩左。
缩左 · l→1:把左端 2 移出,和降到 6 < 7,缩不动了。当前最短仍是 4,继续右扩。
r 扩到 4:r 扩到 4,窗口 [3,1,2,4] 和 = 10 ≥ 7。又能缩左了。
连缩左 · l→3:连续缩左:去掉 3 后 [1,2,4]=7 记长度 3;再去掉 1 后 [2,4]=6 不够,停。最短已是 3。
r 扩到 5:r 扩到最后,窗口 [2,4,3] 和 = 9 ≥ 7,继续缩左找更短。
缩到最短 · [4,3]:去掉左端 2 后 [4,3]=7 ≥ 7,长度 2!这是全程最短,就是答案。
「连续子数组 + 满足某条件求最长/最短」就用滑动窗口:右扩纳入、违规/达标就动左边。无重复最长子串、最小覆盖子串都是它。
参考代码(Python)
Python
1l, s, best = 0, 0, float(class="cl-str">"inf")
2for r in range(len(nums)):
3 s += nums[r] # 右边扩进
4 while s >= target: # 够了就缩左
5 best = min(best, r - l + 1)
6 s -= nums[l]; l += 1
7return 0 if best == float(class="cl-str">"inf") else best复杂度分析
- 时间复杂度:O(n) —— l、r 各走一遍
- 空间复杂度:O(1) —— 几个变量
套路模板
记住骨架:r 右扩纳入、while 里左缩、缩前/后更新答案。求最短在「达标」时更新、求最长在「违规」前更新,是两类窗口的区别。
Python
1# 「连续子数组/子串 + 求最长/最短」都套
2l = 0
3for r in range(n):
4 加入(nums[r]) # 右扩
5 while 窗口违规 or 已达标: # 该缩了
6 更新答案()
7 移出(nums[l]); l += 1 # 左缩易错点
- ❌ 缩窗口时忘了减去左端值 → ✅ s -= nums[l] 再 l += 1(窗口和必须同步维护)
- ❌ 没找到也返回 inf → ✅ 最后判 inf 返回 0(题目要求无解返回 0)
以上文字与上方动画完全同一思路:先看动画建立直觉 → 读文字巩固 → 关掉页面自己默写一遍代码,能写出来才算真的掌握。