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