標籤:sub substring ref span blog find 第一個 end htm
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.
題意:在S中尋找最小包含T的子串,不管字母順序。
思路:採用桶排序。先將T中所有的元素放入hash表中,然後遍曆字串S。如果當前字元在hash表中沒有,說明這個不在T中,則直接跳過。若在,則將hash表中對應的字元的個數減1,說明T中的字元已經找到一個了;此時,若對應字元的個數不小於0,說明這個字元是有效。什麼意思了?如:字串S=“ABAC”找T=“AC”,第一次,找到“A”時,hash表中A對應的個數變為0,即為有效A,計數器count記下了A的個數;再次遇到A時,說明T只有一個A,且已經被記下了,所以不需要再次計數。即,忽略重複的,找到T中全部的就行。那明明是第二個A更符合題意,為什麼要記下第一個A,這個會在後面慢慢的說明。
這樣直到T的中的每個字元都被記下了,且只記下一次。這時,我們更新最小的合乎題意的子字串的長度。這時,我們遇到一個問題,就是,如果開始時,有很多字元不是T中的,但是我們記下的最小字串包括這些,怎麼辦?我們只需不斷的將左指標向右移動,直到遇到第一個在T中的字元,這個過程中,我們不斷的更新minlen長度,這樣我們就得到了這次的複合題意的最下子字串的長度。
那麼我們如何得到下一個符合題意的長度?此時,我們只需將最左端字元在hash表中的個數加1,然後count減1,就實現了,重新尋找下一個子字串的迴圈。因為,會遍曆完S,所以之前說的遇到第二個A時,會重新更新minlen,所以之前只用記住一個A的。參考了Grandyang的部落格。代碼如下:
1 class Solution { 2 public: 3 string minWindow(string S, string T) 4 { 5 if(T.size()>S.size()) return ""; 6 string res=""; 7 int left=0,count=0,minLen=S.size()+1; 8 unordered_map<char,int> m; 9 for(int i=0;i<T.size();++i)10 {11 if(m.find(T[i]) !=m.end())12 ++m[T[i]];13 else14 m[T[i]]=1;15 } 16 17 for(int right=0;right<S.size();++right)18 {19 if(m.find(S[right]) !=m.end())20 {21 --m[S[right]];22 if(m[S[right]]>=0)23 ++count;24 while(count==T.size())25 {26 if(right-left+1<minLen)27 {28 minLen=right-left+1;29 res=S.substr(left,minLen);30 }31 if(m.find(S[left]) !=m.end())32 {33 ++m[S[left]];34 if(m[S[left]]>0)35 --count;36 }37 left++;38 }39 }40 }41 return res;42 }43 };
解題思路:其實就是通過雙指標維持一個Window,視窗右指標向右擴張用來找到包含子串為目的,視窗左指標向右收縮以使子串最小。典型的滑動視窗方法的實現。
也可以用數組來替代hash表,參考 曲高和寡_健的部落格,代碼如下:
1 class Solution { 2 public: 3 string minWindow(string S, string T) 4 { 5 int sLen=S.size(),tLen=T.size(); 6 if(sLen==0||tLen==0) 7 return ""; 8 vector<int> sHash(256,0),tHash(256,0); 9 for(int i=0,i<tLen;++i)10 {11 tHash[T[i]]++;12 } 13 14 int beg=-1,end=sLen,count=0,minLen=sLen;15 for(int i=0,start=i;i<sLen;++i)16 {17 ++sHash[S[i]];18 if(sHash[S[i]]<=tHash[S[i]])19 ++count;20 21 if(count==tLen)22 {23 while(start<i&&sHash[S[start]]>tHash[S[start]])24 {25 --sHash[S[start]];26 start++;27 }28 29 if(i-start<minLen)30 {31 minLen=i-start;32 beg=start;33 end=i;34 }35 36 --sHash[S[start++]]; //尋找下一個符合要求的子字串37 --count;38 }39 }40 if(beg==-1)41 return "";42 return S.substr(beg,end-beg+1);43 44 }45 };
這種方法看的更為清晰些。
[Leetcode] minimum window substring 最小字元視窗