【数据结构与算法】【算法专题】滑动窗口

举报
huahua.Dr 发表于 2023/11/14 23:29:16 2023/11/14
【摘要】 常常使用左右指针解决滑动窗口问题滑动窗口代码框架:void slidingWindow(String s) { // 用合适的数据结构记录窗口中的数据 HashMap<Character, Integer> window = new HashMap<>(); int left = 0, right = 0; while (right < s.length()) { ...

常常使用左右指针解决滑动窗口问题

滑动窗口代码框架:

void slidingWindow(String s) {

    // 用合适的数据结构记录窗口中的数据

    HashMap<Character, Integer> window = new HashMap<>();

    int left = 0, right = 0;

    while (right < s.length()) {

        // c 是将移入窗口的字符

        char c = s.charAt(right);

        window.put(c, window.getOrDefault(c, 0) + 1);

        // 增大窗口

        right++;

        // 进行窗口内数据的一系列更新

        ...

        /*** debug 输出的位置 ***/

        // 注意在最终的解法代码中不要 print

        // 因为 IO 操作很耗时,可能导致超时

        System.out.printf("window: [%d, %d)\n", left, right);

        /********************/

        // 判断左侧窗口是否要收缩

        while (left < right && window needs shrink) {

            // d 是将移出窗口的字符

            char d = s.charAt(left);

            window.put(d, window.get(d) - 1);

            // 缩小窗口

            left++;

            // 进行窗口内数据的一系列更新

            ...

        }

    }

}

运用滑动窗口算法思考的问题

1、什么时候应该扩大窗口?

2、什么时候应该缩小窗口?

3、什么时候应该更新答案?

 

class Solution {

    public String minWindow(String s, String t) {

        HashMap<Character, Integer> window = new HashMap<>();

        HashMap<Character, Integer> need = new HashMap<>();

        for (int i = 0; i < t.length(); i++) {

            need.put(t.charAt(i), need.getOrDefault(t.charAt(i), 0) + 1);

        }

        int left = 0;

        int right = 0;

        int valid = 0;

        int start = 0;

        int len = Integer.MAX_VALUE;

        while(right < s.length()) {

            // 1. 增大窗口操作

            char c = s.charAt(right);

            right ++;

            //1.1 进行窗口更新

            if(need.containsKey(c)) {

                window.put(c, window.getOrDefault(c, 0) +1);

                // 1.2 窗口值跟预期值相等时更新有效值

                if (window.get(c).equals(need.get(c))) {

                    valid ++;

                }

            }

            // 2. 判断是否需要缩小窗口

            while (left < right && valid == need.size()) {

                // 2.1 更新满足条件的开始位置和长度(最短的时候才更新)

                if (right - left < len) {

                    start = left;

                    len = right - left;

                }

                // 2.2 开始缩小窗口

                char d  = s.charAt(left);

                left ++;

                // 2.3 更新窗口的值

                if (need.containsKey(d)) {

                    if (window.get(d).equals(need.get(d))) {

                        // 如果当前还相等,则在缩小窗口前有效值-1

                        valid--;

                    }

                    window.put(d, window.get(d) - 1);

                }

            }

        }

        return len == Integer.MAX_VALUE ? "" : s.substring(start, start + len);

    }

}
  • 使用双指针解决滑窗问题:字符串排列

https://leetcode.cn/problems/permutation-in-string/description/

 

class Solution {

    public boolean checkInclusion(String s1, String s2) {

        if (s1.length() > s2.length()) {

            return false;

        }

        HashMap<Character, Integer> window = new HashMap<>();

        HashMap<Character, Integer> need = new HashMap<>();

        for(char c: s1.toCharArray()) {

            need.put(c, need.getOrDefault(c, 0) +1);

        }

        int left = 0;

        int right = 0;

        int valid = 0;

        while (right < s2.length()) {

            // 增大窗口

            char c = s2.charAt(right);

            right ++;

            // 更新自己的内容

            if (need.containsKey(c)) {

                window.put(c, window.getOrDefault(c, 0) +1);

                if (window.get(c).equals(need.get(c))) {

                    valid ++;

                }                

            }

            // 缩小窗口,查找符合排列的内容

            while (left < right && right - left >= s1.length()) {

                char p = s2.charAt(left);

                left ++;

                if (valid == need.size()){

                    return true;

                }

                if (need.containsKey(p)) {

                    if (window.get(p).equals(need.get(p))) {

                        valid --;

                    }

                    window.put(p, window.getOrDefault(p, 0) -1);

                }

            }

        }

        return false;

    }

}
  • 使用过双针针解决滑动窗口的问题:找到字符串中所有字母异位词

https://leetcode.cn/problems/find-all-anagrams-in-a-string/description/

 

class Solution {

    public List<Integer> findAnagrams(String s, String p) {

        HashMap<Character, Integer> window = new HashMap<>();

        HashMap<Character, Integer> need = new HashMap<>();

        for(char c: p.toCharArray()) {

            need.put(c, need.getOrDefault(c,0) + 1);

        }

        int left = 0;

        int right = 0;

        int valid = 0;

        List<Integer> res = new ArrayList<>();

        while (right < s.length()) {

            char c = s.charAt(right);

            right ++;

            if (need.containsKey(c)) {

                window.put(c, window.getOrDefault(c, 0) + 1);

                if (window.get(c).equals(need.get(c))) {

                    valid ++;

                }

            }

            while (left < right && right - left >= p.length()) {

                char c2 = s.charAt(left);

                if (valid == need.size()) {

                    res.add(left);

                }

                left ++;

                if(need.containsKey(c2)) {

                    if(window.get(c2).equals(need.get(c2))) {

                        valid --;

                    }

                    window.put(c2, window.getOrDefault(c2, 0) -1);

                }

            }

        }

        return res;

    }

}
  • 使用双指针解决滑窗问题:无重复字符的最长子串

https://leetcode.cn/problems/longest-substring-without-repeating-characters/description/

 

class Solution {

    public int lengthOfLongestSubstring(String s) {

        HashMap<Character, Integer> window = new HashMap<>();

        int left = 0;

        int right = 0;

        int res = 0;

        while (right < s.length()) {

            char c= s.charAt(right);

            right++;

            window.put(c, window.getOrDefault(c,0) + 1);

            while(left < right && window.get(c) > 1) {

                char c2 = s.charAt(left);

                left++;

                window.put(c2, window.getOrDefault(c2,0) -1);

            }

            if(right - left > res) {

                res = right - left;

            }            

        }

        return res;

    }

}

其他习题:

package com.huahua.dr.leetcode.string;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

public class KeyWordStr {

    public static void main(String[] args) {
        String[] words = {
                "abbb","def","bbg"
        };
        String inputStr = "aabbbgz";
        HashMap<String,Integer> xjWord = new HashMap<>();
        for (int i = 0; i < words.length; i++) {
            String w1 = words[i];
            for (int j = 0; j < words.length; j++) {
                if (i == j) {
                    continue;
                }
                String w2 =words[j];
                String common = getCommonStr(w1,w2);
                if (!common.isEmpty()) { //相交合并
                    int index = inputStr.indexOf(common);
                    if (index != -1) {
                        xjWord.put(w1,1);
                        xjWord.put(w2,1);
                        if (inputStr.substring(index+common.length()).startsWith("<b>")){
                            inputStr = inputStr.substring(0,index) +"<b>"+common+inputStr.substring(index+common.length()+"<b>".length());
                        } else if (inputStr.substring(0,index).endsWith("</b>")) {
                            inputStr = inputStr.substring(0,index-"</b>".length())+common+"</b>"+inputStr.substring(index+common.length());
                        }else {
                            inputStr = inputStr.substring(0,index) +"<b>"+common+"</b>"+inputStr.substring(index+common.length());
                        }
                    }
                }
            }
            int index = inputStr.indexOf(w1);
            if (index != -1 && !xjWord.containsKey(w1)) {
                if (inputStr.substring(index+w1.length()).startsWith("<b>")){
                    inputStr = inputStr.substring(0,index) +"<b>"+w1+inputStr.substring(index+w1.length()+"<b>".length());
                } else if (inputStr.substring(0,index).endsWith("</b>")) {
                    inputStr = inputStr.substring(0,index-"</b>".length())+w1+"</b>"+inputStr.substring(index+w1.length());
                }else {
                    inputStr = inputStr.substring(0,index) +"<b>"+w1+"</b>"+inputStr.substring(index+w1.length());
                }
            }
        }
        System.out.println(inputStr);
    }



    private static String getCommonStr(String w1, String w2){
        StringBuilder res = new StringBuilder();
        int left = w1.length() -1;
        int right = 0;
        int size = Math.min(w1.length(), w2.length());
        for (int i = 0; i < size; i++) {
            if (w2.charAt(right) == w1.charAt(left)) {
                res.append(w2.charAt(right));
                right++;
                left --;
            } else {
                break;
            }
        }
        if (!res.toString().isEmpty()) {
            int index1 = w1.lastIndexOf(res.toString());
            return w1.substring(0,index1)+ res +w2.substring(res.length());
        }
        return res.toString();
    }
}
  1. https://leetcode.cn/problems/max-consecutive-ones-iii/description/?show=1
  2. https://leetcode.cn/problems/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit/description/?show=1
  3. https://leetcode.cn/problems/minimum-operations-to-reduce-x-to-zero/description/?show=1
  4. https://leetcode.cn/problems/contains-duplicate-ii/description/?show=1
  5. https://leetcode.cn/problems/contains-duplicate-iii/description/?show=1
  6. https://leetcode.cn/problems/longest-substring-with-at-least-k-repeating-characters/description/?show=1
  7. https://leetcode.cn/problems/longest-repeating-character-replacement/description/?show=1
  8. https://leetcode.cn/problems/subarray-product-less-than-k/description/?show=1
  9. https://leetcode.cn/problems/shortest-subarray-with-sum-at-least-k/description/?show=1
  10. https://leetcode.cn/problems/zui-chang-bu-han-zhong-fu-zi-fu-de-zi-zi-fu-chuan-lcof/description/?show=1
  11. https://leetcode.cn/problems/he-wei-sde-lian-xu-zheng-shu-xu-lie-lcof/description/?show=1
  12. https://leetcode.cn/problems/2VG8Kg/description/?show=1
  13. https://leetcode.cn/problems/ZVAVXX/description/?show=1
  14. https://leetcode.cn/problems/MPnaiL/?show=1
  15. https://leetcode.cn/problems/VabMRr/?show=1
  16. https://leetcode.cn/problems/wtcaE1/?show=1
  17. https://leetcode.cn/problems/M1oyTv/?show=1
  18. https://leetcode.cn/problems/7WqeDu/?show=1
【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。