首页 > 代码库 > 【leetcode刷题笔记】Minimum Window Substring

【leetcode刷题笔记】Minimum Window Substring

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.


 

题解:参考leetcode给出的解答,实现了O(n)的算法。

用到的主要变量如下:

设置一个Map:ToFind记录T中出现的字符的种类和个数,我们需要在S中找到这些字符。

设置另一个Map:hasFound记录当前窗口中包含的字符的种类和个数。

这两个Map,结合一个变量count——在当前窗口中找到的T中的字符个数,我们就可以判断当前窗口是否包含T中所有的字符了。

算法的主要过程如下:

  • 当前窗口的起始和结束位置都在S(0)处;
  • 当窗口中没有包含T中所有的字符时(count<T.length),扩展窗口的右端end,直到窗口中包含了T中所有的变量。
  • 此时窗口不一定是最小的,因为左端还有可能缩进,根据窗口的左端变量begin所指的元素,把窗口的左端尽可能右移。
  • 得到一个包含T的窗口,跟最小的窗口比较,如果比最小的窗口小,就更新最小的窗口。

举个例子:S = "acbbaca" , T = "aba"。

如上图所示,end从初始的位置扩展到下面的图中的位置时候,窗口包含了T中所有的字符,而且begin也无法挪动了,此时得到一个最小窗口长度为5;

接下来继续移动end直到下一个包含在T里面的元素处(见第二幅图),然后把begin尽可能往右移动(见第三幅图),得到一个新的当前最小窗口baca,由于它比最小窗口acbba短,所以更新最小窗口为baca。算法结束。

所以我们可以看出begin只有在找到T的时候才右移收缩窗口,而end一直后移。在找到第一个窗口后,end每移动到一个T里面包含的元素处,就会有一个新的窗口(比如上述end从索引为4的地方挪动到索引为6的地方)。

代码如下:

 1 public class Solution { 2     public String minWindow(String S, String T) { 3         HashMap<Character, Integer> needToFind = new HashMap<Character, Integer>(); 4         HashMap<Character, Integer> hasFound = new HashMap<Character, Integer>(); 5         int count = 0; 6          7         for(int i = 0;i < T.length();i++){ 8             char ch_t = T.charAt(i); 9             if(!needToFind.containsKey(ch_t)){10                 needToFind.put(ch_t, 1);11                 hasFound.put(ch_t, 0);12             }13             else {14                 needToFind.put(ch_t, needToFind.get(ch_t)+1);15             }16         }17         18         int minWindowBegin = -1;19         int minWindowEnd = S.length();20         int minWindowLen = S.length();21         for(int begin = 0,end = 0; end < S.length();end++){22             char char_end = S.charAt(end);23             //skip character not in T24             if(!needToFind.containsKey(char_end))25                 continue;26             hasFound.put(char_end, hasFound.get(char_end)+1);27             if(hasFound.get(char_end) <= needToFind.get(char_end))28                 count++;29             30             if(count == T.length()){31                 //narrow down the window as much as possible32                 char char_begin = S.charAt(begin);33                 while(!needToFind.containsKey(char_begin) || hasFound.get(char_begin) > needToFind.get(char_begin)){34                     if(needToFind.containsKey(char_begin) && hasFound.get(char_begin) > needToFind.get(char_begin)){35                         hasFound.put(char_begin, hasFound.get(char_begin)-1);36                     }37                     begin++;38                     char_begin = S.charAt(begin);39                 }40                 41                 int windowLen = end - begin + 1;42                 if(windowLen <= minWindowLen){43                     minWindowBegin = begin;44                     minWindowEnd = end;45                     minWindowLen = windowLen;46                 }47                     48             }49         }50         51         if(count == T.length()){52             StringBuffer sbBuffer = new StringBuffer();53             for(int i = minWindowBegin;i<=minWindowEnd;i++)54                 sbBuffer.append(S.charAt(i));55             return sbBuffer.toString();56         }57         else58             return "";        59     }60 }