76. Minimum Window Substring

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).

Example:

Input: S = "ADOBECODEBANC", T = "ABC"
Output: "BANC"

Note:

  • If there is no such window in S that covers all characters in T, return the empty string "".
  • If there is such window, you are guaranteed that there will always be only one unique minimum window in S.
   public class Solution {
        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 = 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);
        }
    }

转自 https://www.jianshu.com/p/ce80b4c07c22

解题思路其实就是通过双指针维持一个Window,窗口右指针向右扩张用来找到包含子串为目的,窗口左指针向右收缩以使子串最小。
典型的滑动窗口方法的实现。

 sliding window,换了一种好理解的方式:

class Solution {
    public String minWindow(String s, String t) {
        if (s.isEmpty()) return "";
        if (s.length() < t.length()) return "";
        //src stores how many times char in t shows up.
        int src[] = new int[256];
        for(int i = 0; i < t.length(); i++) src[t.charAt(i)]++;
        //minwidth is the width of minimum string in S which contains T.
        int minwidth = Integer.MAX_VALUE;
        //win stores how many times char in s shows up, only store those exist in T.
        int win[] = new int[256];
        int length = 0; //The variable shows how many chars in t has shown in s.
        int wndstart = 0;   //window start position.
        int minstart = 0;   //minimum window start position.
        for(int i = 0; i < s.length(); i++){
            if(src[s.charAt(i)] > 0){
                win[s.charAt(i)]++;
                //To ensure the frequency of a certain char in s not more than in t.
                if(win[s.charAt(i)] <= src[s.charAt(i)]) length++;
            }
            if(length == t.length()){
                //Shorten the meaningless char at the beginning.
                while(src[s.charAt(wndstart)] < win[s.charAt(wndstart)] || src[s.charAt(wndstart)] == 0){
                    win[s.charAt(wndstart)]--;
                    wndstart++;
                }
                if(minwidth > (i - wndstart + 1)){
                    minwidth = (i - wndstart + 1);
                    minstart = wndstart;    //Refresh minstart.
                }
            }
        }
        return minwidth == Integer.MAX_VALUE ? "" : s.substring(minstart, minstart+minwidth);
    }
}

 上面不要看

 

class Solution {
    public String minWindow(String s, String t) {
        int [] map = new int[128];
        for (char c : t.toCharArray()) {
          map[c]++;
        }
        int start = 0, end = 0, minStart = 0, minLen = Integer.MAX_VALUE, counter = t.length();
        while (end < s.length()) {
          final char c1 = s.charAt(end);
          if (map[c1] > 0) counter--;
          map[c1]--;//如果c1存在于t,本来大于0减减后最多等于0,如果不存在,本来等于0减减后会小于0,
          end++;
          while (counter == 0) {
            if (minLen > end - start) {
              minLen = end - start;
              minStart = start;
            }
            final char c2 = s.charAt(start);
            map[c2]++;//还回去
            if (map[c2] > 0) counter++;//如果不存在,还回去最多 == 0,如果m【start】存在于t,那就有可能大于0,所以有此判断
            start++;
          }
        }

        return minLen == Integer.MAX_VALUE ? "" : s.substring(minStart, minStart + minLen);
      }
}

 

https://leetcode.com/problems/minimum-window-substring/discuss/26808/here-is-a-10-line-template-that-can-solve-most-substring-problems

 

class Solution {
    public String minWindow(String s, String t) {
        int le = Integer.MAX_VALUE;
        int[] hash = new int[128];
        
        char[] sarr = s.toCharArray();
        char[] tarr = t.toCharArray();
        for(char c : tarr) hash[c]++;
        
        int sle = s.length(), tle = t.length();
        String res = "";
        int count = 0, l = 0;
        
        for(int r = 0; r < sle; r++) {
            hash[sarr[r]]--;
            if(hash[sarr[r]] >= 0) count++;
            
            while(count == tle) {
                if(r - l + 1 < le) {
                    le = r - l + 1;
                    res = s.substring(l, r + 1);
                }
                hash[sarr[l]]++;
                if(hash[sarr[l]] > 0) count--;
                l++;
            }
        }
        return le == Integer.MAX_VALUE ? "" : res;
    }
}

还是按模板来吧,进入while之后要更新res和l,并且把l还回去(的时候判断count是否变化)

posted @ 2019-03-13 13:12  Schwifty  阅读(188)  评论(0编辑  收藏  举报