LeetCode 209中等滑动窗口
长度最小的子数组 图解题解
这道题到底在问什么
nums 是正整数数组,求和 ≥ target 的最短连续子数组长度;不存在返回 0。
- 输入
- nums=[2,3,1,2,4,3], target=7
- 输出
- 2 (子数组 [4,3])
最优解:一步一步想明白
- 3记住这条「右扩累加、够了就左缩」,下面每一帧都在套它。
- 4右指针扩到下标 0(值 4),累加进窗口 → 窗口和 4。还不够 11,继续右扩。
- 5右指针扩到下标 1(值 2),累加进窗口 → 窗口和 6。还不够 11,继续右扩。
- 6右指针扩到下标 2(值 1),累加进窗口 → 窗口和 7。还不够 11,继续右扩。
- 7右指针扩到下标 3(值 3),累加进窗口 → 窗口和 10。还不够 11,继续右扩。
- 8右指针扩到下标 4(值 2),累加进窗口 → 窗口和 12。已经够 11 了,准备收缩左边求更短。
- 9收缩前先记下长度 5,刷新最短为 5;左指针缩到下标 1,移出后窗口和 8 < 11,这一轮缩不动了,回去继续右扩。
- 10右指针扩到下标 5(值 5),累加进窗口 → 窗口和 13。已经够 11 了,准备收缩左边求更短。
- 11左指针缩到下标 2,移出后窗口和 11 仍 ≥ 11,还能再缩。
- 12收缩前先记下长度 4,刷新最短为 4;左指针缩到下标 3,移出后窗口和 10 < 11,这一轮缩不动了,回去继续右扩。
- 13右指针扩到下标 6(值 1),累加进窗口 → 窗口和 11。已经够 11 了,准备收缩左边求更短。
- 14左指针缩到下标 4,移出后窗口和 8 < 11,这一轮缩不动了,回去继续右扩。
- 15右指针扩到下标 7(值 2),累加进窗口 → 窗口和 10。还不够 11,继续右扩。
- 16右指针扩到下标 8(值 3),累加进窗口 → 窗口和 13。已经够 11 了,准备收缩左边求更短。
- 17左指针缩到下标 5,移出后窗口和 11 仍 ≥ 11,还能再缩。
- 18左指针缩到下标 6,移出后窗口和 6 < 11,这一轮缩不动了,回去继续右扩。
- 19右指针扩到下标 9(值 1),累加进窗口 → 窗口和 7。还不够 11,继续右扩。
- 20右指针扩到下标 10(值 4),累加进窗口 → 窗口和 11。已经够 11 了,准备收缩左边求更短。
- 21左指针缩到下标 7,移出后窗口和 10 < 11,这一轮缩不动了,回去继续右扩。
- 22右指针扩到下标 11(值 2),累加进窗口 → 窗口和 12。已经够 11 了,准备收缩左边求更短。
- 23左指针缩到下标 8,移出后窗口和 10 < 11,这一轮缩不动了,回去继续右扩。
- 24整趟扫完,最短的「和 ≥ 11」窗口长度是 4(绿色高亮)。左右指针各只走一遍,O(n)。
⚠️ 容易写错的地方
✗ 错:用 if 收缩一次就停
✓ 对:要用 while 一直缩到不够为止
一次右扩后可能能连缩好几格才到最短
✗ 错:收缩后忘了更新窗口和
✓ 对:出窗口要 s -= nums[l]
不减就把已移出的元素还算在内
✗ 错:不存在时返回别的值
✓ 对:凑不够 target 必须返回 0
题目明确规定
完整代码(Python / C++ / Java)
Python
def minSubArrayLen(target, nums):
l = s = 0
best = float("inf")
for r in range(len(nums)):
s += nums[r] # 右扩累加
while s >= target: # 够了就收缩
best = min(best, r - l + 1)
s -= nums[l]; l += 1
return 0 if best == float("inf") else bestC++
int minSubArrayLen(int target, vector<int>& nums){
int l = 0, s = 0, best = INT_MAX;
for(int r = 0; r < nums.size(); r++){
s += nums[r];
while(s >= target){
best = min(best, r - l + 1);
s -= nums[l++];
}
}
return best == INT_MAX ? 0 : best;
}Java
public int minSubArrayLen(int target, int[] nums) {
int l = 0, s = 0, best = Integer.MAX_VALUE;
for (int r = 0; r < nums.length; r++) {
s += nums[r]; // 右指针扩窗口累加
while (s >= target) { // 和够了就收缩左指针
best = Math.min(best, r - l + 1);
s -= nums[l++];
}
}
return best == Integer.MAX_VALUE ? 0 : best;复杂度
时间
O(n)
l、r 各最多走一遍,合计线性
空间
O(1)
只用几个指针/累加变量
看不够?换成动画再走一遍
上面的推演每一步都对应一帧动画。点开交互动画版,能一步步看着 长度最小的子数组 的数据怎么变、指针怎么走,还能切 Python / Java / C++ 跟着练。
面试官可能追问
如果数组里有负数还能用滑动窗口吗?+
不能直接用。负数会破坏「缩窗口必定减小和」的单调性,需改用前缀和 + 单调队列(LC862)。
能不能用前缀和 + 二分做到 O(n log n)?+
可以。前缀和递增,对每个右端点二分找最左满足的前缀,是另一种经典解法。
想听吴师兄把这道题讲给你听?
文字版和动画都随便看。开通图解算法年卡,可以听吴师兄把 长度最小的子数组 一步步讲透(全站已上线 905 份讲透,持续扩充), 卡住的地方还有 AI 私教小欧就着动画帮你拆到懂。
本平台为独立第三方培训机构,与华为技术有限公司无任何关联;课程的服务内容与权益以购买协议为准,学习效果因个人情况而异。「华为 OD」「华为可信」等仅为对岗位与考试方向的客观描述,相关商标归各自权利人所有。