LeetCode Hot100 76.最小覆盖子串

题目

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

注意:

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

代码

class Solution {
    //建立两个HashMap,ori用于存储目标字符串t中每个字符的出现次数
    //cnt用于存储当前窗口中每个字符的出现次数。
    Map ori = new HashMap();
    Map cnt = new HashMap();

    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;//l窗口左边界,r窗口右边界
        //ansL和ansR用于存储最小覆盖子串的起始位置和结束位置。
        int len = Integer.MAX_VALUE, ansL = -1, ansR = -1;
        //s串长度
        int sLen = s.length();
        //符合要求的字符数
        int vaild = 0;
        //开始遍历
        while (r < sLen) {
            ++r;
            //遍历原字符串s,右指针r向右移动。若r未越界且当前字符存在于ori中,则将其添加至cnt中并增加其出现次数。
            if (r < sLen && ori.containsKey(s.charAt(r))) {
                //存放窗口内不同目标字符的数量
                cnt.put(s.charAt(r), cnt.getOrDefault(s.charAt(r), 0) + 1);
                //如果对应字符的数量相等了,符合要求的字符数+1
                if(cnt.get(s.charAt(r)).equals(ori.get(s.charAt(r)))) vaild++;
            }
            //判定是否合法
            while (ori.size() == vaild && l <= r) {
                //比较窗口大小,如果你后面符合的窗口都比我现在大,就没必要更新了,继续缩短窗口
                if (r - l + 1 < len) {
                    len = r - l + 1;//更新为窗口大小
                    ansL = l; //符合的左边边界下标就是窗口的左边界
                    ansR = l + len; //符合的右边边界下标
                }
                //若左指针指向的字符存在于ori中,则在cnt中减少其出现次数。(因为现在要开始向后移动窗口的左边界)
                //如果是普通字符就只是简单的移动指针就叫可以了,如果是目标字符,就要减少窗口这个字符的数量
                if (ori.containsKey(s.charAt(l))) {
                    //如果当前数量和需要的数量是一样的,现在减掉了1,就已经不符合了
                    if(ori.get(s.charAt(l)).equals(cnt.get(s.charAt(l)))) vaild--;
                    cnt.put(s.charAt(l), cnt.getOrDefault(s.charAt(l), 0) - 1);
                }
                //窗口左边界向后移动,缩小窗口
                ++l;
            }
        }
        //返回最小覆盖子串,若ansL为-1,则说明不存在,返回空串。否则,返回s中从ansL到ansR的子串
        return ansL == -1 ? "" : s.substring(ansL, ansR);
    }
}

你可能感兴趣的:(算法刷题-子串,leetcode,算法,职场和发展)