https://leetcode.com/problems/minimum-window-substring/
题目大意:给定一个字符串S,和一个字符串T,求S的一个子串,包含T的所有字符,且子串最小。
我们应用滑动窗口的思想,首先我们知道包含T的所有字符,最小的子串一定以T的字符开头以T的字符结尾。两个指针l和r,表示滑动窗口的两端,我们举个例子:
S="ADOBECODEBANC" T="ABC"
建立这样的一个数据结构map<char,int> ump初始为:
A:1
B:1
C:1
语义为A缺少一个,B缺少一个,C缺少一个
设定一个变量sum初始为3,表示总共缺少3个字符,当sum=0的时候表示S的子串包含ABC
l=0,r=0,ump= A:0,B:1,C:1,sum=2
r往右走,走到字符B,ump=A:0,B:0,C:1,sum=1,
r继续往右走,走到字符C,ump=A:0,B:0,C:0,sum=0此时是包含T所有字符的子串了。
l往后走,走到下一个T的字符B,ump=A:1,B:0,C:0,sum=1
r再往后走,走到字符B,此时ump=A:1,B:-1,C:0,sum=1(B多了一个,但是总共还是缺少一个字符A)
然后以此类推走下去,遍历过一次后,找到最小的子串。
#include<bits/stdc++.h>
using namespace std;
class Solution {
public:
string minWindow(string s, string t) {
if(t.size()==0 || s.size()==0) return "";
int l=0,r=-1;
int min_l=0,min_r=INT_MAX-5;
int sum=(int)t.size();
unordered_map<char,int> ump;
for(auto it=t.begin();it!=t.end();++it) ++ump[*it];
for(;l<(int)s.size() && ump.find(s[l])==ump.end();++l);
for(;l<(int)s.size() && r<(int)s.size();){
//cout<<"l="<<l<<" r="<<r<<" sum="<<sum<<endl;
while(r<(int)s.size() && sum!=0){
++r;
//s[r]字符不在t中
if(ump.find(s[r])!=ump.end()){
if(ump[s[r]]>0) --sum;
--ump[s[r]];
if(sum==0){
if(min_r-min_l+1>r-l+1){
min_l=l;
min_r=r;
//cout<<"update,min_l="<<min_l<<" min_r="<<min_r<<endl;
}
break;
}
}
}
//cout<<"mid,l="<<l<<" r="<<r<<" sum="<<sum<<endl;
//l往右
++ump[s[l]];
if(ump[s[l]]>0) ++sum;
++l;
while(l<(int)s.size() && ump.find(s[l])==ump.end()) ++l;
if(sum==0 && min_r-min_l+1>r-l+1){
//cout<<"update,min_l="<<min_l<<" min_r="<<min_r<<endl;
min_l=l;
min_r=r;
}
}
//cout<<"min_l="<<min_l<<" min_r="<<min_r<<endl;
//cout<<"result=";
//for(int i=min_l;i<=min_r;++i) cout<<s[i];
//cout<<endl;
if(min_r==INT_MAX-5) return "";
else{
string ret(s,min_l,min_r-min_l+1);
return ret;
}
}
};