題目:
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.
Hash Table Two Pointers String
在字符串 S 中查找最小的窗口,使窗口中全部包含字符串T 中的字符,(不按順序),需要注意的地方:
- T 中的字符可以重復,窗口需要重復包含。
- 測試 實驗中的是SCII字符 ,所以可以用128位數組代替 hash table。
- leetcode c++ 中不能用 hash_map。
思路:
- 使用一個映射int need(hash table 或者 128位數組) 存儲T中個字符需要的個數,因為需求可能為負,所以用int。
- 使用一個映射bool exitst(hash table 或者 128位數組) 存儲T中個字符是否存在,使用hashtable 也構造這個,因為find 是遍歷查找的。
- 用一個var 記錄窗口中符合T 中char 的個數。
- 用下表start、last 標記窗口位置,start 指向窗口內第一個char,last 指向窗口外右邊第一個char(包括結尾)。
- 每次循環加入或刪除(記錄一個flag)一個字符,如果不存在便繼續循環。
- 通過判斷加入刪除flag進行操作,更新need 表,更新var, 如果等於T 的長度,更新返回記錄。
- 循環結束判斷能否查找。
下面是我寫的,需要的時間復雜度為O(length(S)),即O(n),空間復雜度為O(length(T)):

1 #include <string> 2 #include <hash_map> 3 #include <iostream> 4 #include <map> 5 using namespace std; 6 using namespace __gnu_cxx; 7 8 class Solution { 9 public: 10 string minWindow(string S, string T) { 11 int numS = S.length(),numT = T.length(); 12 if(numS<1||numT<1) return ""; 13 int WinStart=0,WinLast=0,WinCount =0,retStart,leng=INT_MAX; 14 hash_map<char, int > need; 15 hash_map<char, bool > exist; 16 for(int i =0;i<numT;i++){ 17 need[T[i]]++; 18 exist[T[i]] = true; 19 } 20 21 bool addorminus; 22 char curchar; 23 while(WinStart<=numS-numT){ 24 if(WinCount!=numT&&WinLast<numS){ 25 addorminus = true; 26 curchar = S[WinLast++]; 27 } 28 else{ 29 addorminus = false; 30 curchar = S[WinStart++]; 31 } 32 if(!exist[curchar]) continue; 33 if(addorminus){ 34 if(need[curchar]>0) WinCount++; 35 need[curchar]--; 36 if(WinCount==numT&&leng>WinLast - WinStart){ 37 retStart = WinStart; 38 leng = WinLast - WinStart; 39 } 40 } 41 else{ 42 if(WinCount==numT&&leng>WinLast - WinStart+1){ 43 retStart = WinStart-1; 44 leng = WinLast - WinStart+1; 45 } 46 need[curchar] ++; 47 if(need[curchar]>0) WinCount--; 48 } 49 } 50 if(leng==INT_MAX) 51 return ""; 52 return S.substr(retStart,leng); 53 } 54 }; 55 56 int main() 57 { 58 string s = "1A123BAC1"; 59 string t = "AABC"; 60 Solution sol; 61 62 string ret = sol.minWindow(s,t); 63 cout<<ret<<endl; 64 return 0; 65 }
leetcode 討論里面有另外一個實現,也是O(n),實現類似,不同的是循環內是通過判斷窗口中已經有T中字符的個數來進行 add or delete,我寫的是通過目標操作字符來進行,邏輯上沒有ta寫的方便。
https://oj.leetcode.com/discuss/10337/accepted-o-n-solution

1 class Solution { 2 public: 3 string minWindow(string S, string T) { 4 if (S.empty() || T.empty()) 5 { 6 return ""; 7 } 8 int count = T.size(); 9 int require[128] = {0}; 10 bool chSet[128] = {false}; 11 for (int i = 0; i < count; ++i) 12 { 13 require[T[i]]++; 14 chSet[T[i]] = true; 15 } 16 int i = -1; 17 int j = 0; 18 int minLen = INT_MAX; 19 int minIdx = 0; 20 while (i < (int)S.size() && j < (int)S.size()) 21 { 22 if (count) 23 { 24 i++; 25 require[S[i]]--; 26 if (chSet[S[i]] && require[S[i]] >= 0) 27 { 28 count--; 29 } 30 } 31 else 32 { 33 if (minLen > i - j + 1) 34 { 35 minLen = i - j + 1; 36 minIdx = j; 37 } 38 require[S[j]]++; 39 if (chSet[S[j]] && require[S[j]] > 0) 40 { 41 count++; 42 } 43 j++; 44 } 45 } 46 if (minLen == INT_MAX) 47 { 48 return ""; 49 } 50 return S.substr(minIdx, minLen); 51 } 52 };