LeetCode刷题笔记——最小覆盖子串
题目描述
给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字符的最小子串。
示例:
输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"
说明:
如果 S 中不存这样的子串,则返回空字符串 “”。
如果 S 中存在这样的子串,我们保证它是唯一的答案。
思路
本问题要求返回字符串s中包含字符串t的全部字符的最小窗口。我们将包含t的全部字母的窗口称为可行窗口。滑动窗口思想上,有两个指针,一个是用来收缩窗口的l指针,另外一个是用来扩展窗口的r指针。在任意时刻,都只有一个指针在运动,另外一个保持静止。
我们在s上滑动窗口,通过 移动r指针不断扩张窗口 。当窗口包含t全部所需的字符后,如果能收缩,就将窗口收缩直到得到最小窗口, 通过l指针进行收缩。收缩到不满足check条件为止。
主要操作:先进行扩展操作,当扩展到满足check条件后,试图收缩,收缩到不满足check,继续扩展。。。。。。。。
问题:如何判断窗口中包含的t中所需的字符数?用哈希表来保存字符和个数。
class Solution {
public:
unordered_map <char, int> ori, cnt;
bool check() {
for (const auto &p: ori) {
if (cnt[p.first] < p.second) {
return false;
}
}
return true;
}
string minWindow(string s, string t) {
for (const auto &c: t) {
++ori[c];
}
int l = 0, r = -1;
int len = INT_MAX, ansL = -1, ansR = -1;
while (r < int(s.size())) {
if (ori.find(s[++r]) != ori.end()) {
++cnt[s[r]];
}
while (check() && l <= r) {
if (r - l + 1 < len) {
len = r - l + 1;
ansL = l;
}
if (ori.find(s[l]) != ori.end()) {
--cnt[s[l]];
}
++l;
}
}
return ansL == -1 ? string() : s.substr(ansL, len);
}
};
labuladong解法:
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char,int> window,need;
for(char item : t)
need[item]++;
int l=0,r=0;
int valid=0;
int start=0,len=INT_MAX;
while(r<s.size()){
char c=s[r++];
if(need.count(c)){
window[c]++;
if(window[c]==need[c])
valid++;
}
while(valid==need.size()){
if(r-l<len){
start=l;
len=r-l;
}
char d=s[l];
l++;
if(need.count(d)){
if(window[d]==need[d])
valid--;
window[d]--;
}
}
}
return len==INT_MAX? "":s.substr(start,len);
}
};