Leetcode 76. Minimum Window Substring

来源:互联网 发布:天津seo网络推广 编辑:程序博客网 时间:2024/05/20 18:17

76. Minimum Window Substring

Total Accepted: 59573 Total Submissions: 279212 Difficulty: Hard

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 empty string "".

If there are multiple such windows, you are guaranteed that there will always be only one unique minimum window in S.


解法一:

暴力解。从左到右,寻找一个窗口满足包括T。


解法二:

先用HashMap统计t中各个元素和出现的频率。然后从左到右,先将窗口扩到刚好包括T中所有元素,时候相当于右边固定,然后缩小左边。如果左边所指元素在T中没有出现,或者是出现之后当前子串包含的个数大于T中的频率(冗余),也可以缩。当刚好无法再缩小时,计算长度,更新结果。

自己用了两个map,一个是t的统计,另外一个是temp,用于统计当前子串。debug了俩小时,结论是:越是繁琐的代码,越不要复制粘贴,要不然眼花缭乱,找错都要找半天!!

count变量用于统计当前有效字符数,当count==t.length()说明已经找到了满足要求的子串;外层for循环中的变量i其实就是窗口的右指针,所以只要维护一个left指针就可以了,初始位于0的位置。当计算完length之后,left++,移动到下一个子串开始的合法位置。

public class Solution { // 67ms    public String minWindow(String s, String t) {        Map<Character, Integer> tmap = new HashMap<Character, Integer>();        Map<Character, Integer> cmap = new HashMap<Character, Integer>();        for(int i=0; i<t.length(); i++){ // 先统计t中的元素,放入tmap            if(tmap.get(t.charAt(i))==null) tmap.put(t.charAt(i), 1);            else tmap.put(t.charAt(i), tmap.get(t.charAt(i))+1);        }                int left = 0, length = Integer.MAX_VALUE, resStart = -1, count = 0;        for(int i=0; i<s.length(); i++){            if(tmap.get(s.charAt(i))!=null){ // 如果该字符在t中出现                if(cmap.get(s.charAt(i))==null){ // cmap中没有,则计数                   cmap.put(s.charAt(i), 1); count++;                 }else if(cmap.get(s.charAt(i)) < tmap.get(s.charAt(i))){ // cmap中有但数量不够,计数                    count++; cmap.put(s.charAt(i), cmap.get(s.charAt(i))+1);                }else{ // 多余的目标字符,放入,但不计入有效数目                    cmap.put(s.charAt(i), cmap.get(s.charAt(i))+1);                }            }                                if(count==t.length()){ // 当收集够了目标字符                while(true){                    if(tmap.get(s.charAt(left))==null){ // 无关字符,左移指针                        left++;                    }else if(cmap.get(s.charAt(left)) > tmap.get(s.charAt(left))){ //多余字符,左移指针                        cmap.put(s.charAt(left), cmap.get(s.charAt(left))-1); left++;                    }else{ // 已经到了不能删的位置。                        int curlength = i - left + 1;                        if(length > curlength){                            resStart = left;                            length = curlength;                        }                        cmap.put(s.charAt(left), cmap.get(s.charAt(left))-1); left++;                        count--; break;                    }                }            }        }        return resStart==-1 ? "" : s.substring(resStart, resStart + length);    }}

优化:使用俩int[256]数组替代hashmap。

public class Solution { // 7ms    public String minWindow(String s, String t) {        int[] tar = new int[256];        int[] temp = new int[256];        for(int i=0; i<t.length(); i++){            tar[t.charAt(i)]++;        }        int left=0, length=Integer.MAX_VALUE, start=-1, count=0;        char cur;        for(int i=0; i<s.length(); i++){            cur = s.charAt(i);            if(tar[cur]!=0){                if(temp[cur]<tar[cur]){                    temp[cur]++; count++;                }else{                    temp[cur]++;                }            }            if(count==t.length()){                while(true){                    cur = s.charAt(left);                    if(tar[cur]==0){                        left++;                    }else if(tar[cur]<temp[cur]){                        temp[cur]--; left++;                    }else{                        int curlength = i - left + 1;                        if(length>curlength){                            start = left;                            length = curlength;                        }                        temp[cur]--; left++; count--; break;                    }                }            }        }        return start==-1 ? "" : s.substring(start, start + length);    }}


附上一开始参考的地址和其代码:

public class Solution { // 11ms    public String minWindow(String S, String T) {        int[] srcHash = new int[255];        // 记录目标字符串每个字母出现次数        for(int i = 0; i < T.length(); i++){            srcHash[T.charAt(i)]++;        }        int start = 0,i= 0;        // 用于记录窗口内每个字母出现次数         int[] destHash = new int[255];        int found = 0;        int begin = -1, end = S.length(), minLength = S.length();        for(start = 0, i = 0; i < S.length(); i++){            // 每来一个字符给它的出现次数加1            destHash[S.charAt(i)]++;            // 如果加1后这个字符的数量不超过目标串中该字符的数量,则找到了一个匹配字符            if(destHash[S.charAt(i)] <= srcHash[S.charAt(i)]) found++;            // 如果找到的匹配字符数等于目标串长度,说明找到了一个符合要求的子串                if(found == T.length()){                // 将开头没用的都跳过,没用是指该字符出现次数超过了目标串中出现的次数,并把它们出现次数都减1                while(start < i && destHash[S.charAt(start)] > srcHash[S.charAt(start)]){                    destHash[S.charAt(start)]--;                    start++;                }                // 这时候start指向该子串开头的字母,判断该子串长度                if(i - start < minLength){                    minLength = i - start;                    begin = start;                    end = i;                }                // 把开头的这个匹配字符跳过,并将匹配字符数减1                destHash[S.charAt(start)]--;                found--;                // 子串起始位置加1,我们开始看下一个子串了                start++;            }        }        // 如果begin没有修改过,返回空        return begin == -1 ? "" : S.substring(begin,end + 1);    }}


0 0
原创粉丝点击