題目:
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 };
