以leetcode 76. 最小覆盖子串为例,学习滑动窗口的技巧

2022-03-21  本文已影响0人  Burlong

leetcode 76. 最小覆盖子串

用滑动窗口来解答此题,有几个关键点:

一、确认整个遍历操作中我们需要用到的变量

二、确定左边窗口何时向右收敛

三、各个变量在何时被维护?仔细想想,有几个关键时刻:

1、右边窗口往右滑动:

2、每次窗口中字符满足覆盖要求时:

最终返回目标子串即可。

某一时刻的窗口快照.png

代码实现如下:

public class Solution {

    public String minWindow(String s, String t) {
        // 用以记录需要的字符以及每个字符应该出现次数
        Map<Character, Integer> needs = new HashMap<>();
        for(int i = 0; i < t.length(); i++) {
            char c = t.charAt(i);
            needs.put(c, needs.getOrDefault(c, 0) + 1);
        }
        // 用以记录当前窗口中符合needs的字符以及每个字符出现的次数
        Map<Character, Integer> windows = new HashMap<>();
        // 滑动窗口的左右窗口,左闭右开[left,right)
        int left = 0, right = 0;
        // 用来记录结果:子串的开始索引以及长度
        int start = 0, len = Integer.MAX_VALUE;
        // 记录当前窗口中字符出现次数满足needs要求的个数,只有当全部字符出现个数都满足了,左窗口才尝试向右收缩
        int validCount = 0;
        while (right < s.length()) {
            // 往右滑动
            char c = s.charAt(right++);
            // 找到一个需要的字符
            if (needs.containsKey(c)) {
                // 当前窗口统计该字符的hash桶计数器+1
                windows.put(c, windows.getOrDefault(c, 0) + 1);
                // 出现的次数刚好达到要求
                if (windows.get(c).equals(needs.get(c))) {
                    // 表示当前窗口中,当前字符的出现次数已达到要求
                    validCount++;
                }
            }

            // 所有字符的出现字数都满足了,那么准备左边窗口向前收缩(尝试圈一个更小的子串)
            while (validCount == needs.size()) {
                // 每次达到字符数要求,就试图更新一下字串开始索引与长度
                if (right - left < len) {
                    start = left;
                    len = right - left;
                }
                // 左边窗口向前收缩
                char l = s.charAt(left++);
                // 如果收缩前最左边的字符为需要的字符,那么更新当前窗口完成的字符个数,并更新窗口中有效字符个数
                if (needs.containsKey(l)) {
                    // 右移去掉该字符后,出现次数达不到要求,那么符合needs要求的个数要减1
                    if (windows.get(l).equals(needs.get(l))) {
                        validCount--;
                    }
                    windows.put(l, windows.get(l) - 1);
                }
            }
        }
        return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len);
    }

}
上一篇 下一篇

猜你喜欢

热点阅读