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.
//字符串t是可能包含重复字符的,ABCC的前三个元素就能完全包含ABC的字符,故判断窗口何时已完全包含t的字符是个难点
//思路是用双指针维护一个窗口,当窗口完全包含的t的字符时,移动head直到不能再移动为止
public class Solution {
public String minWindow(String s, String t) {
if(s==null || s.length()==0) {
return "";
}
//根据字符串t建立一个字典:map< char, char在t中重复的次数 >
Map<Character, Integer> map = new HashMap<Character, Integer>();
for(int i=0; i<t.length(); i++){
char myChar = t.charAt(i);
if(map.containsKey(myChar)){
map.put(myChar, map.get(myChar)+1);
}else{
map.put(myChar, 1);
}
}
int head = 0; //头指针
int count = 0; //用来判断窗口是否已经完全包含t的字符
int start = 0; //最小窗口的起始位置
int minLength = Integer.MAX_VALUE; //最小窗口的长度
for(int tail=0; tail<s.length(); tail++){ //尾指针不断向后遍历
char tailChar = s.charAt(tail);
if(map.containsKey(tailChar)){ //如果不包含,就直接continue
map.put(tailChar, map.get(tailChar)-1);
if(map.get(tailChar) >= 0){ //在串t中仅出现了一次的char,仅仅能让count加1
count++; //当count加到t.length时,窗口[head-tail]一定完整的包含t串了,只可能多,不可能少
} //若t=ABCC,当tail遍历到窗口ADOBECC的第二个C,此时count=4,但第二个C是多余的
while(count == t.length()){ //此时窗口[head-tail]已经完整包含t了,向右移动head,直到
if(tail-head+1 < minLength){ //窗口不在包含t了
minLength = tail-head+1; //当前的窗口比以前选定的窗口更小,就更新最小窗口
start = head;
}
char headChar = s.charAt(head);
if(map.containsKey(headChar)){ //窗口head处的字符位于串t之中
map.put(headChar, map.get(headChar)+1);
if(map.get(headChar) > 0){ //说明在上面加一操作之前,map.get(headChar)=0
count--; //说明headChar是必须的,不能少了的
}
}
head++;
}
}
}
if(minLength > s.length()){
return "";
}
return s.substring(start, start+minLength);
}
}