LeetCode 209. 长度最小的子数组(Minimum Size Subarray Sum)
✅ 难度:中等
✅ 考察点:滑动窗口 / 双指针 / 前缀和优化
🔗 题目链接
👉 https://leetcode.com/problems/minimum-size-subarray-sum/
📖 题目描述
给定一个含有 n 个正整数的数组和一个正整数 target。
找出 和 ≥ target 的 连续子数组 的 最小长度。
如果不存在,返回 0。
示例
bash
输入:
target = 7
nums = [2,3,1,2,4,3]
输出:
2
解释:
子数组 [4,3] 的和 ≥ 7,且长度最小
💡 解题思路(滑动窗口)
核心思想
由于数组元素 全为正数 ,可以使用 双指针滑动窗口:
- 右指针
i扩张窗口,累加sum - 当
sum ≥ target时:- 更新最小长度
- 左指针
j收缩窗口
- 直到
sum < target
为什么可以用滑动窗口?
✅ 关键性质:
- 所有数都是正数
- 扩大窗口 → sum 增大
- 缩小窗口 → sum 减小
因此不会出现"缩了又变大"的情况。
✅ AC 代码(Java)
✅ 你的 AC 代码(简洁高效)
java
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
int res = Integer.MAX_VALUE;
int sum = 0;
int j = 0; // 左端点
for (int i = 0; i < n; i++) {
sum += nums[i];
while (sum >= target) {
res = Math.min(res, i - j + 1);
sum -= nums[j];
j++;
}
}
return res == Integer.MAX_VALUE ? 0 : res;
}
}
⏱ 复杂度分析
| 项目 | 复杂度 |
|---|---|
| 时间复杂度 | O(n) |
| 空间复杂度 | O(1) |
✅ 每个元素最多被访问两次(一次进窗口,一次出窗口)
⚠️ 注意事项(非常重要)
1️⃣ 必须使用 while,不能用 if
java
while (sum >= target)
❌ 错误:
java
if (sum >= target)
📌 因为可能多次收缩窗口
2️⃣ 返回值的处理
java
return res == Integer.MAX_VALUE ? 0 : res;
✅ 防止无解情况
3️⃣ 为什么不用前缀和 + 二分?
| 方法 | 时间复杂度 |
|---|---|
| 滑动窗口 | O(n) ✅ |
| 前缀和 + 二分 | O(n log n) |
✅ 本题滑动窗口更优
4️⃣ 数组必须为正(关键前提)
❌ 如果有负数:
- 滑动窗口不再适用
- 必须用前缀和 + 二分
🧠 面试加分点
- 明确指出 正数数组 的前提
- 说明 为什么 while 不能换成 if
- 能推导 O(n) 时间复杂度
- 能现场手写出该模板
🔁 滑动窗口通用模板(一维数组)
java
int left = 0;
for (int right = 0; right < n; right++) {
sum += nums[right];
while (sum >= target) {
res = Math.min(res, right - left + 1);
sum -= nums[left];
left++;
}
}
✅ 总结一句话
本题是滑动窗口的经典入门题:右指针扩张,左指针收缩,O(n) 一次遍历完成。