[Leetcode] - Minimum Window Substring

来源:互联网 发布:蜂窝数据突然不显示app 编辑:程序博客网 时间:2024/06/06 00:43

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);    }}

0 0