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.
使用两个指针start和end去截取S中的字符串,初始都为S头部。end指针先往后遍历,直到T中所有字符都出现在子字符串中或者到S结尾,这时候把start往后挪,尽量使子串长度小,直到再往后挪就会不满足T中字符都在子串中的条件或者到达end,这时候记录start和end并计算子串长度,如果比之前的小则更新start和end。如此反复这两步直到end到S末尾。
问题是两个关键时刻:1.T中所有字符都出现在子字符串中;2. 再往后挪就会不满足T中字符都在子串中的条件,该怎么被捕获。
使用两个HashMap可以实现。第一个HashMap, need记录关于T中所有字符的次数统计,在遍历S中作为标准,不会变化。第二个HashMap, found记录遍历过程中字符出现次数的动态变化。
条件2可以这么实现: 一旦发现found中当前字符(前提是存在于found中)的值已经等于need中的值,则停止start指针的遍历。否则可以继续遍历不过found中的值要-1。
条件1可以联系T的长度来实现:使用变量count记录已在S中找到的T中字符个数。一旦count等于T的长度,开始把start往后挪。那么,什么样的字符是已在S中找到的T中字符,可以算进count?依然使用found和need可以判断,如果found中字符的值小于等于need中它的值,说明这遍历到的字符应该算进count,因为关于这个字符,还没有或者刚刚好满足它应该出现的次数,应该要算作T中字符。而若found中的值大于need中的值,说明该已经遍历到足够多该字符,不需要再来这种字符了,需要的是T中其他的字符,所以不能算进count.
1 public String minWindow(String S, String T) { 2 if(T.length()>S.length()) 3 return ""; 4 HashMap<Character, Integer> need = new HashMap<Character, Integer>(); 5 HashMap<Character, Integer> found = new HashMap<Character, Integer>(); 6 7 for(int i=0;i<T.length();i++) { 8 char t = T.charAt(i); 9 if(!need.containsKey(t)) { 10 need.put(t,1); 11 found.put(t,0); 12 } else 13 need.put(t, need.get(t)+1); 14 } 15 int start = 0; 16 int end = 0; 17 int minStart = -1; 18 int minEnd = S.length(); 19 int count = 0; 20 for(;end<S.length();end++) { 21 char t = S.charAt(end); 22 if(need.containsKey(t)) { 23 found.put(t, found.get(t)+1); 24 if(found.get(t)<=need.get(t)) 25 count++; 26 if(count==T.length()) { 27 for(;start<=end;start++) { 28 char t2 = S.charAt(start); 29 if(need.containsKey(t2)) { 30 if(found.get(t2)>need.get(t2)) 31 found.put(t2, found.get(t2)-1); 32 else 33 break; 34 } 35 } 36 if(start>end) 37 start--; 38 if(end-start<minEnd-minStart) { 39 minStart = start; 40 minEnd = end; 41 } 42 } 43 } 44 } 45 return minStart==-1?"":S.substring(minStart,minEnd+1); 46 }