题目
Given a string S and a string T, find the minimum window in S which will contain all the characters in T in complexity O(n).
For example,
S = "ADOBECODEBANC"
T = "ABC"
Minimum window is "BANC"
.
Note:
If there is no such window in S that covers all characters in T, return the empty string ""
.
If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.
分析讨论区有一篇文章列举了解子串问题的模板,可以解最小子串,最大子串等问题,参考文章:Here is a 10-line template that can solve most 'substring' problems
需要注意其中技巧,测试s=EFABDCBA,t=ABC可以看到全部情况
class Solution {
public:
string minWindow(string s, string t) {
vector<int> map(128,0);//保存目标串t中字母的出现次数
for(auto c: t)
map[c]++;
int counter=t.size(), begin=0, end=0, d=INT_MAX, head=0;//counter设置为t串长度,head作为最终子串的起始下标,d保存最小的窗口大小,begin和end则是作为匹配过程中子串的中间索引变量
while(end<s.size()){//end遍历字符串s
if(map[s[end++]]-->0) //map中保存t中字符出现次数,如果s[end]在map中出现,则map[s[end]]>0,判断后次数减1,代表匹配成功一个字符,并且counter-1,代表t中剩余需要匹配个数-1,每次操作后end后移一位
counter--; //in t
while(counter==0){ //当counter=0时,代表t中字符都在s中出现过,end此时在最后一个出现的字符后面
if(end-begin<d) //先计算一下窗口大小,修改窗口值
d=end-(head=begin);
if(map[s[begin++]]++==0)
counter++; //begin从前向后移动,如果map[s[begin]]=0,则代表该处字符在t中出现过,此时由于已经计算过子串长度,可以将该字符索引+1,并且counter+1,随后begin后移,窗口除去该字符,开始新的匹配;如果s[begin]不是在t中出现的字符,或者s[begin]在t中出现,但是end后移时提前遍历到了该字符,比如在s=EFABDCBA,t=ABC中,begin=2,end=6是第一个窗口,计算后A的索引+1,begin后移到3,即B的位置,counter+1后等于1,此时end在第一个if会将B的索引减1,为-1,并且没改变counter值,然后end继续到7处,A索引减1为0,counter为0,end置位8,进入循环,begin为3,B索引-1,则此时map[s[begin]]<0,不会修改counter值,begin得以后移,找到最小窗口
}
}
return d==INT_MAX? "":s.substr(head, d);
}
};