leetcode
 
解题思路
该问题需要找到字符串 s 中包含 t 所有字符的最小子串,且需满足字符出现次数的要求。核心解决方法是 滑动窗口 配合 哈希表 或 数组 统计字符频率,通过动态调整窗口边界实现高效搜索。
 
关键步骤
- 初始化统计:统计 
t 中字符的出现次数,存入哈希表或数组。 
- 滑动窗口维护:
- 右指针扩展窗口:逐个将字符加入窗口,更新统计信息。
 
- 左指针收缩窗口:当窗口满足条件时,尝试缩小窗口以寻找最小覆盖子串。
 
 
- 条件判断:通过比较窗口内字符频率与 
t 的频率,确定是否满足要求。 
- 更新结果:记录最小窗口的起始位置和长度。
 
复杂度分析
- 时间复杂度:O(M + N),其中 M 是 
t 的长度,N 是 s 的长度。每个字符最多被左右指针各遍历一次。 
- 空间复杂度:O(C),C 为字符集大小(如 ASCII 对应 128),用于存储字符频率。
 
代码实现
func minWindow(s string, t string) string {
    if len(s) == 0 || len(t) == 0 || len(s) < len(t) {
        return ""
    }
    // 统计 t 的字符频率
    tFreq := make(map[byte]int)
    for i := 0; i < len(t); i++ {
        tFreq[t[i]]++
    }
    windowFreq := make(map[byte]int)  // 窗口内字符频率
    left, right := 0, 0               // 滑动窗口左右指针
    valid := 0                        // 满足 t 频率要求的字符种类数
    minLen := math.MaxInt32            // 最小窗口长度
    start := 0                        // 最小窗口起始位置
    for right < len(s) {
        c := s[right]
        right++
        // 若当前字符在 t 中,更新窗口统计
        if _, exists := tFreq[c]; exists {
            windowFreq[c]++
            if windowFreq[c] == tFreq[c] {
                valid++
            }
        }
        // 当窗口包含所有 t 的字符时,尝试收缩左边界
        for valid == len(tFreq) {
            // 更新最小窗口
            if right - left < minLen {
                minLen = right - left
                start = left
            }
            // 移动左指针
            d := s[left]
            left++
            if _, exists := tFreq[d]; exists {
                if windowFreq[d] == tFreq[d] {
                    valid-- // 移除后不再满足条件
                }
                windowFreq[d]--
            }
        }
    }
    if minLen == math.MaxInt32 {
        return ""
    }
    return s[start : start+minLen]
}
 
 
 
代码注释
- 初始化统计:用 
tFreq 存储 t 的字符频率,windowFreq 统计窗口内字符。 
- 滑动窗口逻辑:
- 右指针扩展:将字符加入窗口,若其频率与 
t 匹配,则 valid 增加。 
- 左指针收缩:当 
valid 等于 t 的字符种类数时,尝试缩小窗口并记录最小值。 
 
- 边界处理:若未找到有效窗口,返回空字符串;否则返回子串。
 
运行示例
func main() {
    // 示例 1
    s1 := "ADOBECODEBANC"
    t1 := "ABC"
    fmt.Println(minWindow(s1, t1)) // 输出: "BANC"
    // 示例 2
    s2 := "a"
    t2 := "a"
    fmt.Println(minWindow(s2, t2)) // 输出: "a"
    // 示例 3
    s3 := "a"
    t3 := "aa"
    fmt.Println(minWindow(s3, t3)) // 输出: ""
}
 
 
 
示例解析
- 示例 1:窗口逐步扩展至包含 "A", "B", "C",最终在 "BANC" 处找到最小子串。
 
- 示例 2:单个字符直接匹配。
 
- 示例 3:
t 要求两个 'a',但 s 只有一个,返回空。