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 emtpy string""
.
If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.
思路:
题目对时间复杂度要求很高。首先要考虑简化T和S的运算。T中只要统计不同字母个数即可,而S中只有相应T的字母及其位置才有意义。所以先把这些内容抽出来放到一个hash中简化计算。然后考虑的是如何在S中寻找满足T的子串。这时可以使用两个指针指向简化后的S(记作S'),一个向前移动(r_iter),一个不动(l_iter)。在r_iter向前移动到l_iter和r_iter之间的内容满足要求时,检查是否比之前找到的子串短。之后再移动l_iter,并相应的移动r_iter直到找到下一个满足要求的子串。略微复杂的是,可能在这一段中,一个字母被用的次数多于T中给出的次数,这时需要将多余的字母个数计数,但是却又不能计算在和T比较的字母长度之中。这样,扫视一次T和S可以看作O(2n),而两个指针的扫视是O(n)。总共时间是O(3n)。
题解:
class Solution { public: string minWindow(string S, string T) { enum { CHR_MAX = 256 }; // Empty input if (T == "" || S == "") return string(""); array<int, CHR_MAX> TUsage; // character count in string T // setup the T list to hash the characters fill(begin(TUsage), end(TUsage), 0); for(auto ch : T) // hash all used characters ++TUsage[ch]; const size_t T_CHARS = T.size(); vector<pair<char, size_t>> SUsage; // characters from T in S size_t offset = 0; for(auto ch : S) { if (TUsage[ch] != 0) SUsage.push_back(make_pair(ch, offset)); ++offset; } // minimum window range size_t min_l = 0, min_r = S.size()+1; size_t old_minl = min_r - min_l; // record the current window character usage size_t tchar_used = 0; array<int, CHR_MAX> ChUsage; fill(begin(ChUsage), end(ChUsage), 0); // the search window left/right iterator vector<pair<char, size_t>>::const_iterator l_iter = SUsage.begin(); vector<pair<char, size_t>>::const_iterator r_iter = l_iter; size_t new_minl; // scan the SUsage while(l_iter < SUsage.end()) { while(r_iter < SUsage.end() && tchar_used < T_CHARS) { char ch = r_iter->first; ++ChUsage[ch]; // register the used character if (ChUsage[ch] <= TUsage[ch]) ++tchar_used; ++r_iter; } if (tchar_used == T_CHARS) { // verify if it is the minimum window new_minl = (r_iter - 1)->second - l_iter->second + 1; if (new_minl < old_minl) { min_r = (r_iter - 1)->second; min_l = l_iter->second; old_minl = new_minl; } // now do the next iteration --ChUsage[l_iter->first]; if (ChUsage[l_iter->first] < TUsage[l_iter->first]) --tchar_used; ++l_iter; } else break; // cannot find any more windows } if (min_r == S.size() + 1) return string(""); else return S.substr(min_l, min_r - min_l + 1); } };