1. 程式人生 > >[Leetcode] minimum window substring 最小字符窗口

[Leetcode] minimum window substring 最小字符窗口

為什麽 目的 -s pan 遍歷 uno 一個 tro you

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             else
14                 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 最小字符窗口