Minimum Covering Substrings

LeetCode 76

Problem Statement

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

Note

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

Sample #1

1
2
3
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解释:最小覆盖子串 "BANC" 包含来自字符串 t 的 'A'、'B' 和 'C'。

Sample #2

1
2
3
输入:s = "a", t = "a"
输出:"a"
解释:整个字符串 s 是最小覆盖子串。

Sample #3

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

Constraints

  • m == s.length
  • n == t.length
  • 1 <= m, n <= 105
  • st 由英文字母组成

Solving

滑动窗口典型例题,我们维护一个CNT欠款数组,每当右边界遍历到新的字符时实现CNT[s[r]]++,当且仅当此字符CNT<0即属于t串所欠字符时算为有效还款。不断滑动窗口找出所有欠款还清时的左边界和此时的窗口长度,利用substr返回字串即可。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
class Solution {
public:
    string minWindow(string s, string t) {
        if(s.size()<t.size()) return "";
        int tl = t.size();
        int cnt[267] = {0};
        int debt = tl;
        int ans = INT_MAX;
        for(int i=0;i<tl;i++)
        {
            cnt[(int)t[i]]--;
        }
        int start = 0;
        string ansstr = "";
        for(int l=0,r=0;r<s.size();r++)
        {
            if(cnt[s[r]]<0)
            {   
                debt--;
            }
            cnt[s[r]]++;
            if(debt==0)
            {
                while(cnt[s[l]]>0)
                {
                    cnt[s[l++]]--;
                }
                if(r-l+1<ans)
                {
                    ans = r-l+1;
                    start = l;
                }
            }
        }
        return ans==INT_MAX?"":s.substr(start,ans);
    }
};
Licensed under CC BY-NC-SA 4.0
Member of the Qilu University Of Technology ACM-ICPC Association
Built with Hugo
Theme Stack designed by Jimmy