最小覆盖子串
给出两个字符串 s 和 t,要求在 s 中找出最短的包含 t 中所有字符的连续子串。
数据范围:0 > |S|,|T| \le100000>∣S∣,∣T∣≤10000,保证s和t字符串中仅包含大小写英文字母
要求:进阶:空间复杂度 O(n)O(n) , 时间复杂度 O(n)O(n)
例如:
S ="XDOYEZODEYXNZ"S=“XDOYEZODEYXNZ”
T =“XYZ"T=“XYZ”
找出的最短子串为"YXNZ”“YXNZ”.
注意:
如果 s 中没有包含 t 中所有字符的子串,返回空字符串 “”;
满足条件的子串可能有很多,但是题目保证满足条件的最短的子串唯一。
string minWindow(string S, string T) {
// write code here
int a[26]={0},b[26]={}; //标记大小写字母个数,a为大写字母,b为小写字母
int size,i,l,r,sum,len,ans;
char c;
size=T.size();
for(i=0;i<size;i++){ //统计个数
if(T[i]<'a'){
b[T[i]-'A']++;
} else{
a[T[i]-'a']++;
}
}
for(i=0;i<26;i++){ //不在T中的标记为负
if(!a[i]){
a[i]=-20000;
}
if(!b[i]){
b[i]=-20000;
}
}
len = S.size();
for(i=0;i<len&&(S[i]>='a'&&a[S[i]-'a']<=0||S[i]<'a'&&b[S[i]-'A']<=0);i++); //找出S中第一个在T中的字母
l=i; //l标记S中其实位置
ans=0;
int p1,p2; //p1为起始位置,p2为覆盖字串最小长度
p1=-1,p2=INT_MAX;
int tmp;
for(;i<len;i++){
if(S[i]<'a'){ //匹配则相应位置减少
tmp=--b[S[i]-'A'];
} else{
tmp=--a[S[i]-'a'];
}
if(tmp>=0){ //如果tmp>=0说明S中没有重复多余的S[i],匹配度增加
ans++;
}
if(S[l]==S[i]){
while(l<=i){ //判断S中的重复字母是否可以删除
if(S[l]<'a'){
tmp=b[S[l]-'A'];
} else{
tmp=a[S[l]-'a'];
}
if(tmp>=0){ //无重复,不可删除
break;
} else{
if(S[l]<'a'){
++b[S[l]-'A'];
} else{
++a[S[l]-'a'];
}
l++; //起始位置右移
}
}
}
if(ans==size){ //如果完全匹配,与当前字串比较大小
if(i-l+1<p2){
p2=i-l+1;
p1=l;
}
}
}
if(p2==INT_MAX){
return "";
} else{
return S.substr(p1,p2);
}
}