Minimum Window Substring
Difficulty:Hard
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.
题目就是要在S中找到包含T中所有字符的最短子串,包含即可不需要顺序也相同,要求时间复杂度O(n)。
一开始想了几个方法复杂度都不是O(n),想了很久才想出一个办法。
先用一个数组compare记录T中所有字符的重复次数,即ASCii码从33到126的范围内计算,一共93种字符,例如T="aab<"就是2个a、1个b和一个<。
另一个数组match记录当前已满足的字符数,当match中所数都大于等于compare的时候就是找到了一个匹配
例外还有一个链表matchStr记录满足的字符的位置,当match中所有数没有都大于等于compare的时候,其中match大于compare的数就是有多余的字符,应该尽可能的去除这些字符,但是只能从链表的头部开始去除。
当找到了一个匹配后,通过删除去除满足字符的头,让匹配继续往后找。
string minWindow(string s, string t) {
int start = -1;
int end = s.size()+1;//end一开始大于S的size保证第一次匹配时能够赋值
vector<int> compare(93, 0);//需要满足的字符串个数
vector<int> match(93, 0);//已经满足的字符串个数
list<pair<int, char>> matchStr;//满足的字符串
for (int i = 0; i < t.size(); i++){ //计算每个字符需要的数量
compare[(int)(t[i]-33)]++;
}
for (int i = 0; i < s.size(); i++){
if (t.find(s[i]) != t.npos){//判断当前字符是否包含在T中
pair<int, char> p(i, s[i]);//加入满足队列
matchStr.push_back(p);
match[(int)(s[i] - 33)]++;//满足数增加
while (match[(int)(matchStr.front().second - 33)]>compare[(int)(matchStr.front().second - 33)]){//从头开始去除超出的满足字符
match[(int)(matchStr.front().second - 33)]--;
matchStr.pop_front();
}
bool isMatch = true;
for (int j = 0; j < match.size(); j++){//判断当前是否包含足够的字符
if (match[j] < compare[j])
isMatch = false;
}
if (isMatch){//包含足够的字符
if (i - matchStr.front().first < end - start){//是否比已找到的子串更短
start = matchStr.front().first;
end = i;
}
match[(int)(matchStr.front().second - 33)]--;//去除满足字符的头,让匹配继续往后找
matchStr.pop_front();
while (match[(int)(matchStr.front().second - 33)]>compare[(int)(matchStr.front().second - 33)]){//再从头开始去除超出的满足字符
match[(int)(matchStr.front().second - 33)]--;
matchStr.pop_front();
}
}
}
}
if (start < 0 )//通过start判断是否有找到匹配
return "";
else
return s.substr(start, end - start + 1);
}