【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 T
24             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 possible
32                 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         else
58             return "";        
59     }
60 }

 

转载于:https://www.cnblogs.com/sunshineatnoon/p/3870054.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值