Golang 滑动窗口模板与套路详解
针对 LeetCode 1004(最大连续1的个数 III)这类问题,以下是专门为 Golang 开发者准备的滑动窗口实现模板、适用场景和常见变种:
Golang 滑动窗口模板(1004 类型)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| func longestOnes(nums []int, k int) int { left, maxLen, zeroCount := 0, 0, 0
for right := 0; right < len(nums); right++ { if nums[right] == 0 { zeroCount++ } for zeroCount > k { if nums[left] == 0 { zeroCount-- } left++ } if windowSize := right - left + 1; windowSize > maxLen { maxLen = windowSize } } return maxLen }
|
核心套路与技巧(Golang 实现)
双指针初始化:
1 2 3
| left := 0 maxLen := 0 counter := 0
|
右指针移动逻辑:
1 2 3 4 5
| for right := 0; right < len(nums); right++ { if condition(nums[right]) { counter++ }
|
窗口收缩条件:
1 2 3 4 5 6
| for counter > k { if condition(nums[left]) { counter-- } left++ }
|
结果更新:
1 2 3
| if windowSize := right - left + 1; windowSize > maxLen { maxLen = windowSize }
|
Golang 常见变种实现
1. 替换后的最长重复字符(LeetCode 424)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| func characterReplacement(s string, k int) int { count := make([]int, 26) left, maxCount, maxLen := 0, 0, 0 for right, ch := range s { count[ch-'A']++ if count[ch-'A'] > maxCount { maxCount = count[ch-'A'] } if (right-left+1)-maxCount > k { count[s[left]-'A']-- left++ } if windowSize := right-left+1; windowSize > maxLen { maxLen = windowSize } } return maxLen }
|
2. 水果成篮(LeetCode 904)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| func totalFruit(fruits []int) int { basket := make(map[int]int) left, maxFruits := 0, 0 for right, fruit := range fruits { basket[fruit]++ for len(basket) > 2 { basket[fruits[left]]-- if basket[fruits[left]] == 0 { delete(basket, fruits[left]) } left++ } if windowSize := right-left+1; windowSize > maxFruits { maxFruits = windowSize } } return maxFruits }
|
3. 最小覆盖子串(LeetCode 76)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| func minWindow(s string, t string) string { need := make(map[byte]int) window := make(map[byte]int) for i := range t { need[t[i]]++ } left, valid := 0, 0 start, length := 0, math.MaxInt32 for right := 0; right < len(s); right++ { c := s[right] if _, exists := need[c]; exists { window[c]++ if window[c] == need[c] { valid++ } } for valid == len(need) { if right-left+1 < length { start = left length = right - left + 1 } d := s[left] if _, exists := need[d]; exists { if window[d] == need[d] { valid-- } window[d]-- } left++ } } if length == math.MaxInt32 { return "" } return s[start : start+length] }
|
滑动窗口适用场景总结
问题特征 | 示例题目 | Golang 实现要点 |
---|
有限修改连续序列 | 1004, 424, 2024 | 使用计数器跟踪修改需求 |
不同元素数量限制 | 904, 340 | 使用 map 跟踪元素种类 |
最短满足条件子串 | 209, 76 | 收缩时更新最小值 |
固定窗口大小 | 643, 1343 | 维护固定大小的窗口 |
无重复字符 | 3, 159 | 使用 map 或 set 检测重复 |
Golang 实现技巧
计数器选择:
- 简单计数:
int
变量 - 字符频率:
[26]int
或 [128]int
- 通用元素:
map[type]int
边界处理:
1 2 3 4
| if len(nums) == 0 { return 0 }
|
性能优化:
- 避免不必要的内存分配(预分配 map 大小)
- 使用数组代替 map 当键范围有限时
- 减少循环内部的计算
复杂条件处理:
1 2 3 4
| for !isValid(window, condition) { }
|
掌握这些 Golang 实现的滑动窗口模式和变种,能高效解决 LeetCode 上大部分滑动窗口问题。关键是根据问题特征选择合适的计数器类型和窗口收缩条件。