/
Week 5 @ 2025 算法周记【滑动窗口】
In progress
Week 5 @ 2025 算法周记【滑动窗口】
滑动窗口
LC 76. Minimum Window Substring 最小覆盖子串
https://leetcode.com/problems/minimum-window-substring/
func minWindow(s string, t string) string {
expect := toNumArray(t)
window := newNumArray()
result := ""
left, right := 0, 0
for right < len(s) {
window.Add(s[right])
right++
for left < right && window.GreaterThanOrEqual(expect) {
window.Remove(s[left])
result = shorter(result, s[left:right])
left++
}
}
return result
}
type NumArray []int
func newNumArray() NumArray {
return make(NumArray, 52)
}
func (arr NumArray) Add(c byte) {
arr[toNum(c)]++
}
func (arr NumArray) Remove(c byte) {
arr[toNum(c)]--
}
func (arr NumArray) GreaterThanOrEqual(another NumArray) bool {
for i := range arr {
if arr[i] < another[i] {
return false
}
}
return true
}
func toNumArray(s string) NumArray {
arr := newNumArray()
for i := range s {
arr.Add(s[i])
}
return arr
}
func toNum(c byte) int {
if c >= 'a' && c <= 'z' {
return int(c - 'a')
}
if c >= 'A' && c <= 'Z' {
return int(c - 'A') + 26
}
return -1
}
func shorter(base, s string) string {
if base == "" || len(s) < len(base) {
return s
}
return base
}
优化
利用统计「满足窗口条件的字符数」减少 GreaterThanOrEqual 判断的成本
func minWindow(s string, t string) string {
expect := toNumArray(t)
window := newNumArray()
result := ""
valid := 0
expectValid := 0
for _, c := range expect {
if c > 0 {
expectValid++
}
}
left, right := 0, 0
for right < len(s) {
rx := toNum(s[right])
right++
if expect[rx] > 0 {
window[rx]++
if window[rx] == expect[rx] {
valid++
}
}
for left < right && valid == expectValid {
lx := toNum(s[left])
if expect[lx] > 0 {
if window[lx] == expect[lx] {
valid--
}
window[lx]--
}
result = shorter(result, s[left:right])
left++
}
}
return result
}
type NumArray []int
func newNumArray() NumArray {
return make(NumArray, 52)
}
func toNumArray(s string) NumArray {
arr := newNumArray()
for i := range s {
arr[toNum(s[i])]++
}
return arr
}
func toNum(c byte) int {
if c >= 'a' && c <= 'z' {
return int(c - 'a')
}
if c >= 'A' && c <= 'Z' {
return int(c - 'A') + 26
}
return -1
}
func shorter(base, s string) string {
if base == "" || len(s) < len(base) {
return s
}
return base
}
LC 567. Permutation in String 字符串的排列
https://leetcode.com/problems/permutation-in-string/
func checkInclusion(s1 string, s2 string) bool {
expect := toNumberMap(s1)
window := newNumberMap()
valid := 0
expectValid := 0
for _, c := range expect {
if c > 0 {
expectValid++
}
}
left, right := 0, 0
for right < len(s2) {
rx := toNumber(s2[right])
if expect[rx] > 0 {
window[rx] ++
if expect[rx] == window[rx] {
valid++
}
}
right++
for left < right && valid == expectValid {
lx := toNumber(s2[left])
if expect[lx] > 0 {
if expect[lx] == window[lx] {
valid--
}
window[lx]--
}
if right-left == len(s1) {
return true
}
left++
}
}
return false
}
type NumberMap []int
func newNumberMap() NumberMap {
return make(NumberMap, 26)
}
func toNumberMap(s string) NumberMap {
m := newNumberMap()
for i := range s {
m[toNumber(s[i])]++
}
return m
}
func toNumber(c byte) int {
return int(c - 'a')
}
思路二:定长窗口
LC 438. Find All Anagrams in a String 找到字符串中所有字母异位词
https://leetcode.com/problems/find-all-anagrams-in-a-string/
LC 3. Longest Substring Without Repeating Characters 无重复字符的最长子串
https://leetcode.com/problems/longest-substring-without-repeating-characters/
简化判断逻辑
(时间复杂度一样,但是似乎总执行时间没有上面引入 dup 做判断好 7ms vs 0ms - 当然不确定是否是 leetcode 的原因)