-
LeetCode 部分
- 题目链接:leetcode.cn/problems/mi…
- 难度:中等
- 时间复杂度:O(n)(每个元素最多进出窗口一次)
- 空间复杂度:O(1)
- 核心思路(简短): 使用滑动窗口(左、右指针),不断扩大右指针累加和。当窗口和 ≥ target 时,尝试缩小左指针,更新最小长度。窗口始终保持“和 ≥ target”的最小可能。
- 代码(Go 版本,标准滑动窗口写法):
Go
func minSubArrayLen(target int, nums []int) int {
n := len(nums)
if n == 0 {
return 0
}
left := 0
sum := 0
minLen := n + 1 // 初始化为不可能的大值
for right := 0; right < n; right++ {
sum += nums[right] // 扩大窗口
// 窗口和满足条件时,尽量缩小左边界
for sum >= target && left <= right {
minLen = min(minLen, right-left+1)
sum -= nums[left] // 缩小窗口
left++
}
}
if minLen == n+1 {
return 0
}
return minLen
}
// 辅助函数
func min(a, b int) int {
if a < b {
return a
}
return b
}
- C++ 版本(如果你想双语放一个简洁版):
C++
int minSubArrayLen(int target, vector<int>& nums) {
int n = nums.size();
if (n == 0) return 0;
int left = 0, sum = 0, minLen = n + 1;
for (int right = 0; right < n; ++right) {
sum += nums[right];
while (sum >= target && left <= right) {
minLen = min(minLen, right - left + 1);
sum -= nums[left++];
}
}
return minLen == n + 1 ? 0 : minLen;
}
-
易错点/优化点:
- 内层 while:当 sum >= target 时不断缩小左指针,直到不满足为止(这样保证每次都取到当前最小)。
- 初始化 minLen 为 n+1,最后判断是否更新过。
- 数组元素都是正整数 → 右指针只需向右移动一次,O(n) 时间。
- 示例:target = 7, nums = [2,3,1,2,4,3] → 2(子数组 [4,3]) target = 4, nums = [1,4,4] → 1([4])
-
知识点部分(滑动窗口模板总结) 可变滑动窗口通用模板(今天重点)
- 核心:右指针一直扩张,左指针只在满足条件时收缩。
- 适用场景:最小/最大长度子数组、包含所有字符的最小子串等。
- 与固定窗口(如字母异位词)的区别:固定窗口长度不变,这里长度动态变化。
- 面试常问:如果数组有负数怎么办?(滑动窗口失效,需要前缀和 + 哈希或二分)。
- 今天这题因为“正整数”才能用滑动窗口,记住这个前提。
-
今日感悟 这道题把滑动窗口的“收缩”逻辑体现得淋漓尽致,以前我总是把左右指针搞混,今天手写完才真正理解“右扩左缩”的节奏。公开打卡让我必须把边界和初始化处理干净,不然发出去自己都心虚。Day 8 了,坚持两周快到了,感觉技术自信在一点点回来!
-
结束语 明天见! 欢迎评论区:① 你的滑动窗口写法有什么不同? ② 代码哪里还能优化 ③ 你刷滑动窗口系列时最大的收获是什么? #程序员打卡 #LeetCode #滑动窗口 #长度最小的子数组 #Go语言 #C++