给定一个字符串 S 和一个字符串 T,请在 S 中找出包含 T 所有字母的最小子串。
示例:
输入: S = "ADOBECODEBANC", T = "ABC"
输出: "BANC"
说明:
- 如果 S 中不存这样的子串,则返回空字符串
""
。 - 如果 S 中存在这样的子串,我们保证它是唯一的答案。
分析:对于s,t分别创建两个表,存储其中字母出现的次数,在s中寻找,并比较两个表,如果t中的每个字母在s都存在一次,则更新最小长度的值。遍历完成后返回最小的长度。
class Solution {
public:
bool is_window_ok(int map_s[],int map_t[],vector<int>&vec_t){
for(int i=0;i<vec_t.size();i++){
if(map_s[vec_t[i]]<map_t[vec_t[i]]){//s表中没有完全包含t则这次比较是错误的需要继续遍历
return false;
}
}
return true;
}
string minWindow(string s, string t) {
const int max=128;//asc码表的值,将字母转换成数字处理
int map_s[max]={0};
int map_t[max]={0};
vector<int>vec_t;
for(int i=0;i<t.length();i++){
map_t[t[i]]++;//统计那些字母在t中出现
}
for(int i=0;i<max;i++){
if(map_t[i]>0){
vec_t.push_back(i);//在向量中存入出现的字母数值
}
}
int begin=0;
string result="";
for(int i=0;i<s.length();i++){
map_s[s[i]]++;//统计当前s遍历中字母出现的次数
while(begin<i){//头要小于尾,begin是头,i是尾巴
char ch=s[begin];
if(map_t[ch]==0){//如果是t中没有的值,则头节点向前遍历
begin++;
}
else if(map_s[ch]>map_t[ch]){//如果遍历到t中包含的字母且第二次出现
map_s[ch]--;//且出现的次数减一
begin++;//头节点越过
}
else//两种情况都不是,则不进行while循环,取比较是否是包含t的子集
{
break;
}
}
if(is_window_ok(map_s,map_t,vec_t)){//是包含的子集
int len=i-begin+1;//计算当前段的长度
if(result==""||result.length()>len){
result=s.substr(begin,len);//更新最小串
}
}
}
return result;
}
};