76. 最小覆盖子串 完整题解 刷题笔记

Posted dlage

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了76. 最小覆盖子串 完整题解 刷题笔记相关的知识,希望对你有一定的参考价值。

76. 最小覆盖子串
leetcode 刷题笔记。

完整题解:

public class demo76 
    public static void main(String[] args) 
        demo76 demo76 = new demo76();
        String s = demo76.minWindow("abaacbab", "abc");
        System.out.println("最小子字符串是:" + s);
    

    Map<Character, Integer> ori = new HashMap<Character, Integer>();
    Map<Character, Integer> cnt = new HashMap<Character, Integer>();

    public String minWindow(String s, String t) 
        int tLen = t.length();
        // 将t中的全部字符解析出来放在ori中
        for (int i = 0; i < tLen; i++) 
            char c = t.charAt(i);
            ori.put(c, ori.getOrDefault(c, 0) + 1);
        
        // 定义两个指针来控制滑动窗口的位置
        int l = 0, r = -1;
        // 这个len是用来记录最小子串长度的
        int len = Integer.MAX_VALUE, ansL = -1, ansR = -1;
        int sLen = s.length();
        while (r < sLen) 
            ++r;
            if (r < sLen && ori.containsKey(s.charAt(r))) 
                // 如果右指针这个字符属于目标字符,就把它放进cnt里面
                cnt.put(s.charAt(r), cnt.getOrDefault(s.charAt(r), 0) + 1);
            
            // 将左指针右移,并将对应的元素移除
            while (check() && l <= r) 
                // 更新最小长度,并记录最小长度的子字符串
                if (r - l + 1 < len) 
                    len = r - l + 1;
                    ansL = l;
                    ansR = l + len;
                
                // 如果左指针指向的这个字符串为目标字符串,则将它从cnt中移除。
                if (ori.containsKey(s.charAt(l))) 
                    cnt.put(s.charAt(l), cnt.getOrDefault(s.charAt(l), 0) - 1);
                
                ++l;
            
        
        return ansL == -1 ? "" : s.substring(ansL, ansR);
    
    // 检查滑动窗口包含的字符串是否包含所有的字符。
    public boolean check() 
        Iterator iter = ori.entrySet().iterator();
        while (iter.hasNext()) 
            Map.Entry entry = (Map.Entry) iter.next();
            Character key = (Character) entry.getKey();
            Integer val = (Integer) entry.getValue();
            if (cnt.getOrDefault(key, 0) < val) 
                return false;
            
        
        return true;
    



核心代码:

其他部分可以先不用看。看这部分的代码即可,它的两个while循环控制着左右指针的移动。

外层的while控制右指针的移动。无论左指针怎么移动,右指针都会从左到右的遍历一遍。

如上图:右指针遍历到C之前,都不会进入到第二个while循环。因为不满足条件,在窗口中并没有包含所有的目标字符。直到遍历到C时(这时左指针还在开始的位置,就是A),窗口内包含了所有的目标字符(ABC),这时第二个循环的条件满足了,就进入到了第二个循环。

while (r < sLen) 
    ++r;
    if (r < sLen && ori.containsKey(s.charAt(r))) 
        // 如果右指针这个字符属于目标字符,就把它放进cnt里面
        cnt.put(s.charAt(r), cnt.getOrDefault(s.charAt(r), 0) + 1);
    
    // 将左指针右移,并将对应的元素移除
    while (check() && l <= r) 
        // 更新最小长度
        if (r - l + 1 < len) 
            len = r - l + 1;
            ansL = l;
            ansR = l + len;
        
        // 如果左指针指向的这个字符串为目标字符串,则将它从cnt中移除。
        if (ori.containsKey(s.charAt(l))) 
            cnt.put(s.charAt(l), cnt.getOrDefault(s.charAt(l), 0) - 1);
        
        ++l;
    

第一次进入第二个循环:

|abaac|bab,第一个竖线是左指针,第二个竖线是右指针。由于第二个循环控制左指针,左指针会一直向右移动(此时右指针不动),直到这里左指针走到这 ab|aac|bab,这个情况下滑动窗口已经不满足包含所有目标字符的条件了。就不会进入到第二个循环。此时记录最小子字符串的长度为4。

第二次进入第二个循环:

第二次循环是这个样子的 ab | aacb | ab,此时是满足条件的,但是不会更新最小长度,因为他的长度还是4,上一次最小长度也是4。此时左指针向右移动aba | acb | ab,此时长度为3,比4小,会更新最小长度


此时已经是子字符串的最小长度了,后面不会再更新最小长度的值了,但是循环会一直进行下去。

ref:滑动窗口算法解决子串问题

以上是关于76. 最小覆盖子串 完整题解 刷题笔记的主要内容,如果未能解决你的问题,请参考以下文章

76. 最小覆盖子串 完整题解 刷题笔记

[leetcode] 76. 最小覆盖子串

精选力扣500题 第60题 LeetCode 76. 最小覆盖子串c++/java详细题解

Leetcode第76题:最小覆盖子串

5-106-(LeetCode- 76) 最小覆盖子串

leetcode-76 最小覆盖子串