滑动窗口、双指针

237 阅读1分钟

可以解决的问题

  1. 嵌套循环问题

  2. 子串问题:最小覆盖子串,长度最小的子数组

  3. 常见题目

    1. 无重复字符的最长子串
    2. 最小覆盖子串
    3. 串联所有单词的子串
    4. 至多包含两个不同字符的最长子串
    5. 长度最小的子数组
    6. 滑动窗口最大值
    7. 字符串的排列
    8. 最小窗口子序列

滑动窗口框架套路

滑动窗口的大致逻辑框架,伪代码如下:

        int left =0,right = 0;
        string res = s;
        while(right < s.size()) {
            window.add(s[right]);
            right++;
            // 如果符合要求,移动 left 缩⼩窗⼝
            while (window 符合要求) {
                // 如果这个窗⼝的⼦串更短,则更新 res
                res = minLen(res, window);
                window.remove(s[left]);
                left++;
            }
        }
        return res;

基本流程

  • 首先呢,就是获取原字符串的长度。
  • 接着维护一个窗口(数组、哈希、队列)
  • 窗口一步一步向右扩展
  • 窗口在向右扩展滑动过程,需要判断左边是否需要缩减
  • 最后比较更新答案

算法思路

  • 1、我们在字符串 S 中使⽤双指针中的左右指针技巧,初始化 left = right = 0,把索引闭区间 [left, right] 称为⼀个「窗⼝」。
  • 2、我们先不断地增加 right 指针扩⼤窗⼝ [left, right],直到窗⼝中的字符串 符合要求(包含了 T 中的所有字符)。
  • 3、此时,我们停⽌增加 right,转⽽不断增加 left 指针缩⼩窗⼝ [left, right],直到窗⼝中的字符串不再符合要求(不包含 T 中的所有字符了)。 同时,每次增加 left,我们都要更新⼀轮结果。
  • 4、重复第 2 和第 3 步,直到 right 到达字符串 S 的尽头。
  • 滑动窗⼝技巧 285 这个思路其实也不难,第 2 步相当于在寻找⼀个「可⾏解」,然后第 3 步在 优化这个「可⾏解」,最终找到最优解。左右指针轮流前进,窗⼝⼤⼩增增 减减,窗⼝不断向右滑动。

最小覆盖子串

    public String minWindow(String s, String t) {
        Map<Character, Integer> winMap = new HashMap<>();
        Map<Character, Integer> tMap = new HashMap<>();
        for (int i = 0; i < t.length(); i++) {
            tMap.put(t.charAt(i), tMap.getOrDefault(t.charAt(i), 0) + 1);
        }
        int left = 0;
        int start = 0;
        int right = 0;
        int total = 0;
        int len = Integer.MAX_VALUE;
        while (right < s.length()){
            char c = s.charAt(right);
            if (tMap.containsKey(c)) {
                winMap.put(c, winMap.getOrDefault(c, 0) + 1);
                if (winMap.get(c).equals(tMap.get(c)) ) {
                    total++;
                }
            }
            while (total == tMap.size()) {
                if (right - left + 1 < len) {
                    len = right - left + 1;
                    start = left;
                }
                char lChar = s.charAt(left++);
                if (winMap.containsKey(lChar)) {
                    if (winMap.get(lChar).equals(tMap.get(lChar))) {
                        total--;
                    }
                    winMap.put(lChar, winMap.get(lChar) - 1);
                }
            }
            right++;
        }
        return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len);
    }