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 ,求 S 中包含所有 T 中字符的最小子字符串。
值得一提的是,“包含所有 T 中的字符”,是要包含 T 中所有字符以及对应的个数。在 T 中重复出现的字符,在最后答案中也需要包含相同个数的重复字符。第一次解没有理解到这个点,提出结果错误,意识到这个点后,修正并提交成功。
解题思路采用的也是 滑动窗口算法(Slide Window Algorithm),LeetCode 把这样的算法归类到 双指针(Two Pointers)类型,算法思路和前面的 Longest Substring Without Repeating Characters 以及 Minimum Size Subarray Sum 相似。
设下标 l 和 r,把左开右闭 [l, r) 想象成一个窗口。
- 当窗口包含所有 T 中的字符时,则此时的窗口是一个可行解,l++
- 当窗口没有包含所有 T 中的字符时,则 r++;
如何判断窗口是否包含所有 T 中的字符呢?我使用了 map<char, alphStatus> 来表示,其中 alphStatus 只包含两个值:对应的字符在 T 中出现次数(target),以及当前窗口包含该字符的个数(cur)。可见,当 cur > target 时,对应字符满足被包含条件。
当所有字符都满足被包含条件时,当前窗口便是一个可行解。
找出所有可行解中窗口最小的,便是原题目的解。
class alphStatus{ public: int target = 0; int cur = 0; }; string minWindow(string s, string t) { if (s.size() == 1) { return (s == t) ? s : ""; } int l = 0; int r = 1; map<char, alphStatus> alph_status; for (int i = 0 ; i < t.size(); i++) { alph_status[t[i]].target++; } if (alph_status.count(s[0]) != 0) { alph_status[s[0]].cur = 1; } string res = s + "$"; while (r <= s.size()) { bool isAllConted = true; map<char, alphStatus>::iterator m_iter; for (m_iter = alph_status.begin(); m_iter != alph_status.end(); m_iter++) { if (m_iter->second.cur < m_iter->second.target) { isAllConted = false; break; } } if ( isAllConted ) { if (r-l < res.size()) { res = s.substr(l, r-l); } if (alph_status.count(s[l]) != 0) { alph_status[s[l]].cur--; } l++; }else{ if (r < s.size() && alph_status.count(s[r]) != 0) { alph_status[s[r]].cur++; } r++; } } return ((int)res.size() == (int)s.size()+1) ? "" : res; }