您的位置:首页 > 其它

[Leetcode] - Minimum Window Substring

2014-03-10 04:09 375 查看
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.

今天在看编程之美的时候看到了类似的题目(3.5 最短摘要的生成),所以把这道题拿出来复习,总结一下。
这个题目的思路是这样的,首先定义两个HashMap,其形式均为HashMap<Character, Integer>。其中一个map_t用来记录字符串T中每个字符出现的个数,这个需要做pre-processing。另外一个map_s,是动态变化的,里面的内容随着循环的进行而不断的变化着。与此同时,我们还需要定义一个关键的变量用于记录T中所有字符在当前S字符串的窗口中出现的总次数,这里用appear来表示这个变量。也就是说,当appear的长度等于字符串T的长度时,我们可以确定,S字符串的当前窗口里包含了字符串T的所有字符至少一次。注意是至少一次,因为可能会有这种情况出现:比如S=ABCBD,T=ABD,这样的话,最小窗口应该是“ABCBD”,可以看到B出现了两次,而A和D各出现一次。那么如何更新map_s的内容呢?对于每一个S中的字符c,我们先检查c是否在map_t之中,若不在,则直接continue。若在,再检查c是否在map_s中,若不在,将其put进去,然后appear的值加1,这是因为T中每个字符必然至少出现一次。若c在map_s中,那么只有当c在map_s中对应的value小于其在map_t中对应的value值时,才另appear加1,这是因为,map_t中每个字符对应的value是这个字符在字符串S的窗口中应该要出现的次数。还需注意,除了更新appear之外,还有更新字符c在map_s中对应的value的值,这个值将用于对窗口的缩减。那么怎么缩小这个窗口呢?从最左边开始,依次测试每个字符,若该字符在map_s中对应的value等于其在map_t中对应的value,则当前窗口已经缩至最小,记录下当前窗口大小,继续将右侧指针右移。否则,则可以将左侧指针左移以缩小窗口的大小。注意缩减窗口的同时更新map_s中相应字符对应的value值。最后,还要对S中不包含T的全部字符这种edge
case做一下特殊处理,比如,可以用一个变量flag等。
可以看到,对于每个S中的字符c,这种做法最多将c加入窗口1次,且最多将c从窗口中删除1次。因此,时间复杂度为O(n)。

代码如下:
public class Solution {
public String minWindow(String S, String T) {
if(S==null || T==null || S.length()<T.length()) return "";

// the hash map of string T
HashMap<Character, Integer> map_t = new HashMap<Character, Integer>();
for(int i=0; i<T.length(); i++) {
if(!map_t.containsKey(T.charAt(i))) map_t.put(T.charAt(i), 0);
map_t.put(T.charAt(i), map_t.get(T.charAt(i))+1);
}

HashMap<Character, Integer> map_s = new HashMap<Character, Integer>();
int min=Integer.MIN_VALUE, max=Integer.MAX_VALUE, left=0; // min, max->final result, left->left pointers
int appear = 0; // the number of characters of T appearance in the current substring of S, core logic
for(int right=0; right<S.length(); right++) {
char current = S.charAt(right);

// current character is contained by T
if(map_t.containsKey(current)) {
// first appear of this character in S, since it must appear at least one time in T, we can put 1 directly
if(!map_s.containsKey(current)) {
map_s.put(current, 1);
appear++;
}
// current character appears more times in T than in S
else {
if(map_s.get(current)<map_t.get(current)) appear++;
map_s.put(current, map_s.get(current)+1);
}
}

// current window contains all characters in T
// once appear is eqaul to T.length(), it cannot be reduced during the rest iteration
if(appear >= T.length()) {
// shrink the left pointer of the window
while(left < S.length()) {
char minChar = S.charAt(left);
// this character is contained by string T
if(map_t.containsKey(minChar)) {
// we should futhur determine whether we can remove it from the current window
if(map_s.get(minChar) > map_t.get(minChar)) {
map_s.put(minChar, map_s.get(minChar)-1);
left++;
}
else break;
}
// this character is not contained by string T, so we just increment the left pointer
else left++;
}

// update the window pointers if necessary
if(max==Integer.MAX_VALUE || max-min>right-left) {
max = right;
min = left;
}
}
}

if(min==Integer.MIN_VALUE) return "";
else return S.substring(min, max+1);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: