Loading...

为什么你的滑动窗口总是写不对

在这里插入图片描述

求解思路

这道题直接求解很困难,因为我们既要保证每种字符出现次数≥k,又要让子串尽可能长,这两个条件相互制约难以平衡。

但如果我们换个角度,先固定子串中必须恰好包含require种不同的字符,然后在这个约束下用滑动窗口找最长子串,问题就变得简单了。我们从require=1开始枚举到require=26(英文字母最多26种),对于每个require值,用双指针维护一个窗口,右指针不断扩展收集字符,当窗口中的字符种类数超过require时,左指针就收缩窗口把多余的字符吐出去,在满足"种类数等于require且每种字符次数都≥k"这个条件时更新答案。

代码实现

 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
public static int longestSubstring(String str, int k) {
    char[] s = str.toCharArray();
    int n = s.length;
    int[] cnts = new int[256];
    int ans = 0;
    
    // 枚举子串中字符的种类数
    for (int require = 1; require <= 26; require++) {
        Arrays.fill(cnts, 0);
        // collect: 窗口中字符的种类数
        // satisfy: 窗口中出现次数≥k的字符种类数
        for (int l = 0, r = 0, collect = 0, satisfy = 0; r < n; r++) {
            // 右指针扩展窗口
            cnts[s[r]]++;
            if (cnts[s[r]] == 1) {
                collect++;  // 新增一种字符
            }
            if (cnts[s[r]] == k) {
                satisfy++;  // 该字符达标
            }
            
            // 左指针收缩窗口,保证种类数不超过require
            while (collect > require) {
                if (cnts[s[l]] == 1) {
                    collect--;
                }
                if (cnts[s[l]] == k) {
                    satisfy--;
                }
                cnts[s[l++]]--;
            }
            
            // 当所有字符都达标时更新答案
            if (satisfy == require) {
                ans = Math.max(ans, r - l + 1);
            }
        }
    }
    return ans;
}

如果觉得有帮助,欢迎点赞、关注、转发~

最后更新于 2026-04-05 17:35:33
Code Road Record