76. Minimum Window Substring
题目描述和难度
- 题目描述:
给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。
示例:
输入: S = "ADOBECODEBANC", T = "ABC" 输出: "BANC"
说明:
- 如果 S 中不存这样的子串,则返回空字符串 ""。
- 如果 S 中存在这样的子串,我们保证它是唯一的答案。
- 题目难度:困难。
- 英文网址:76. Minimum Window Substring 。
- 中文网址:76. 最小覆盖子串 。
思路分析
求解关键:使用滑动窗口的思想,并且使用两个字符计数数组。先复习第 438 题再做这题可能会好些,解决它们都用了相同的策略。
- S 的字符计数数组记录了当前滑动窗口包括的字符的个数,是动态变化的。
- T 的字符计数数组记录了字符串 T 中的字符的个数,扫描过一次以后这个数组我们不去动它,用来和 S 的字符计数数组进行对应位置上的比较。
参考解答
参考解答1
import java.util.HashSet;
import java.util.Set;
public class Solution {
    public String minWindow(String s, String t) {
        int[] cntS = new int[256];
        int[] cntT = new int[256];
        Set<Character> set = new HashSet<>();
        // cntT 赋值了以后,就成为了用于比对的对象,不更新
        for (char ct : t.toCharArray()) {
            cntT[ct]++;
            set.add(ct);
        }
        int minSub = s.length() + 1;
        String res = "";
        int left = 0;
        int right = 0;
        int count = 0;
        while (right < s.length()) {
            char rc = s.charAt(right);
            if (!set.contains(rc)) {
                // 不在字典里面,但是右边界同样要扩充,所以 right++
                right++;
                continue;
            }
            cntS[rc]++;
            right++;
            // 理解这里是关键:加上以后,小于等于,count 才 ++,
            if (cntS[rc] <= cntT[rc]) {
                // count++; 这件事情说明滑动窗口里面的有效字符,向目标字符又近了一步
                count++;
            }
            // 下面这一段可以写得更精简一些,但是为了语义上的清晰,我就写得冗长一些
            if (count == t.length()) {
                // 接下来,考虑左边界移出滑动窗口
                // 不在字典中,或者多了的时候,直接划掉就可以了
                while (true) {
                    char deleteChar = s.charAt(left);
                    if (!set.contains(deleteChar)) {
                        left++;
                        continue;
                    }
                    if (cntS[deleteChar] > cntT[deleteChar]) {
                        cntS[deleteChar]--;
                        left++;
                        continue;
                    }
                    break;
                }
                if (right - left < minSub) {
                    minSub = right - left;
                    res = s.substring(left, right);
                }
            }
        }
        if (minSub == s.length() + 1) {
            return "";
        }
        return res;
    }
    public static void main(String[] args) {
        Solution solution = new Solution();
        String S = "ADOBECODEBANC";
        String T = "ABC";
        String minWindow = solution.minWindow(S, T);
        System.out.println(minWindow);
    }
}
本篇文章的地址为 https://liweiwei1419.github.io/leetcode-solution/leetcode-0076-minimum-window-substring ,如果我的题解有错误,或者您有更好的解法,欢迎您告诉我 liweiwei1419@gmail.com 。