【算法】滑动窗口

滑动窗口算法可以用以解决数组/字符串的子元素问题,它可以将嵌套的循环问题,转换为单循环问题,降低时间复杂度。

介绍

滑动窗口算法思路很简单:维护一个窗口,不断滑动,然后更新答案。

下面提供一种滑动窗口算法的框架:

public boolean checkInclusion(String s1, String s2) {
        //先将s1转换成hashmap
        HashMap need = new HashMap<>();
        for (int i = 0; i < s1.length(); i++){
            char t = s1.charAt(i);
            need.put(t, need.getOrDefault(t,0)+1);
        }

        //准备滑动窗口,hashmap的window,left,right,vaild标志位
        HashMap window = new HashMap<>();
        int left = 0;
        int right = 0;
        int vaild = 0;

        //开始滑动窗口
        while (right < s2.length()){
            //c将要移入窗口的字符
            char c = s2.charAt(right);
            right++;
            //进行窗口内数据的更新
            if (need.containsKey(c)){
                window.put(c,window.getOrDefault(c,0)+1);
                if (need.get(c).equals(window.get(c))){ //为什么要判断这个,就是要用标志位来标记数量相等
                    vaild++;
                }
            }

            //处理左边界移动
            while (right - left >= s1.length()){
                //当标志位等于need的长度说明两个刚好相同
                if (vaild == need.size()){
                    return true;
                }
                //t表示将要移出窗口的字符
                char t = s2.charAt(left);
                left++;
                if (need.containsKey(t)){
                    if (need.get(t).equals(window.get(t))){
                        vaild--;
                    }
                    window.put(t,window.getOrDefault(t,0)-1);
                }
            }
        }
        return false;
    }

题目

LeetCode76 最小覆盖子串

题目

给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 "" 。

注意:

对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。 如果 s 中存在这样的子串,我们保证它是唯一的答案。

示例 1:

输入:s = "ADOBECODEBANC", t = "ABC" 输出:"BANC" 示例 2:

输入:s = "a", t = "a" 输出:"a" 示例 3:

输入: s = "a", t = "aa" 输出: "" 解释: t 中两个字符 'a' 均应包含在 s 的子串中, 因此没有符合条件的子字符串,返回空字符串。

思路

对于子串的题目,优先想到滑动窗口。

题目中要求s中涵盖t中所有字符的最小子串,那么有几点:

1、s涵盖t中所有字符

2、s是最小子串

那么需要滑动窗口含有t中的所有字符,并且要是最小的。

因此,我们用一个标志valid来判断是否窗口中元素的个数和t中的一致。

代码如下

import java.util.HashMap;

public class leetcode76 {
    public String minWindow(String s, String t) {
        //用hashmap将t转换成hashmap结构
        HashMap need = new HashMap<>();
        for (int i = 0; i < t.length(); i++){
            char ts = t.charAt(i);
            need.put(ts, need.getOrDefault(ts,0)+1);
        }

        //定义一个hashmap,作为窗口window,左右分别为left,right,长度len,标志位vaild,最后左边起始start
        HashMap window = new HashMap<>();
        int left = 0;
        int right = 0;
        int len = Integer.MAX_VALUE;
        int vaild = 0;
        int start = 0;

        //开始滑动窗口
        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))){
                    vaild++; //表示窗口中一个元素的个数和t中的一样
                }
            }
            //判断是否需要滑动窗口
            while (vaild == need.size()){
                if (right - left < len){
                    start = left;
                    len = right - left;
                }
                char l = s.charAt(left);
                left++;
                if (need.containsKey(l)){
                    if (window.get(l).equals(need.get(l))){
                        vaild--;
                    }
                    window.put(l, window.getOrDefault(l,0)-1);
                }
            }
        }
        if (len == Integer.MAX_VALUE){
            return "";
        } else {
            return s.substring(start,start+len);
        }
    }

    public static void main(String[] args) {
        leetcode76 le = new leetcode76();
        String s = "ADOBECODEBANC";
        String t = "ABC";
        System.out.println(le.minWindow(s,t));

    }
}

你可能感兴趣的:(算法,算法)