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