Hard!
題目描述:
給定一個字符串 S 和一個字符串 T,請在 S 中找出包含 T 所有字母的最小子串。
示例:
輸入: S = "ADOBECODEBANC", T = "ABC" 輸出: "BANC"
說明:
- 如果 S 中不存這樣的子串,則返回空字符串
""
。 - 如果 S 中存在這樣的子串,我們保證它是唯一的答案。
解題思路:
這道題的要求是要在O(n)的時間度里實現找到這個最小窗口字串,那么暴力搜索Brute Force肯定是不能用的,我們可以考慮哈希表,其中key是T中的字符,value是該字符出現的次數。
- 我們最開始先掃描一遍T,把對應的字符及其出現的次數存到哈希表中。
- 然后開始遍歷S,遇到T中的字符,就把對應的哈希表中的value減一,直到包含了T中的所有的字符,紀錄一個字串並更新最小字串值。
- 將子窗口的左邊界向右移,略掉不在T中的字符,如果某個在T中的字符出現的次數大於哈希表中的value,則也可以跳過該字符。
C++解法一:
1 class Solution { 2 public: 3 string minWindow(string S, string T) { 4 if (T.size() > S.size()) return ""; 5 string res = ""; 6 int left = 0, count = 0, minLen = S.size() + 1; 7 unordered_map<char, int> m; 8 for (int i = 0; i < T.size(); ++i) { 9 if (m.find(T[i]) != m.end()) ++m[T[i]]; 10 else m[T[i]] = 1; 11 } 12 for (int right = 0; right < S.size(); ++right) { 13 if (m.find(S[right]) != m.end()) { 14 --m[S[right]]; 15 if (m[S[right]] >= 0) ++count; 16 while (count == T.size()) { 17 if (right - left + 1 < minLen) { 18 minLen = right - left + 1; 19 res = S.substr(left, minLen); 20 } 21 if (m.find(S[left]) != m.end()) { 22 ++m[S[left]]; 23 if (m[S[left]] > 0) --count; 24 } 25 ++left; 26 } 27 } 28 } 29 return res; 30 } 31 };
這道題也可以不用哈希表,直接用個int的數組來代替,因為ASCII只有256個字符,所以用兩個大小為256的int數組即可代替哈希表,其余部分的思路完全相同。
C++解法二:
1 class Solution { 2 public: 3 string minWindow(string S, string T) { 4 if (T.size() > S.size()) return ""; 5 string res = ""; 6 int left = 0, count = 0, minLen = S.size() + 1; 7 int tm[256] = {0}, sm[256] = {0}; 8 for (int i = 0; i < T.size(); ++i) ++tm[T[i]]; 9 for (int right = 0; right < S.size(); ++right) { 10 if (tm[S[right]] != 0) { 11 ++sm[S[right]]; 12 if (sm[S[right]] <= tm[S[right]]) ++count; 13 while (count == T.size()) { 14 if (right - left + 1 < minLen) { 15 minLen = right - left + 1; 16 res = S.substr(left, minLen); 17 } 18 if (tm[S[left]] != 0) { 19 --sm[S[left]]; 20 if (sm[S[left]] < tm[S[left]]) --count; 21 } 22 ++left; 23 } 24 } 25 } 26 return res; 27 } 28 };