NC28:最小覆盖子串
最小覆盖子串
http://www.nowcoder.com/questionTerminal/c466d480d20c4c7c9d322d12ca7955ac
解法1:滑动窗口
转载链接:https://leetcode-cn.com/problems/minimum-window-substring/solution/hua-dong-chuang-kou-ji-bai-liao-100de-javayong-hu-/
思路:
新建一个needs[255] 用来统计t中每个字符出现次数,新建一个 window[255]用来统计滑动窗口中每个字符出现次数。首先统计出T中每个字母出现的次数. 新建两个变量left和right分别用来表示滑动窗口的左边和右边。新建一个变量count来表示目前窗口中已经找到了多少个字符。
以S = "ADOBECODEBANC", T = "ABC"为例,然后按照如图所示的规律滑动窗口
即可得出最小子串的长度为4,最小子串为"BANC"
public static String minWindow(String s, String t) { if (s == null || s == "" || t == null || t == "" || s.length() < t.length()) { return ""; } //用来统计t中每个字符出现次数 int[] needs = new int[128]; //用来统计滑动窗口中每个字符出现次数 int[] window = new int[128]; for (int i = 0; i < t.length(); i++) { needs[t.charAt(i)]++; } int left = 0; int right = 0; String res = ""; //目前有多少个字符 int count = 0; //用来记录最短需要多少个字符。 int minLength = s.length() + 1; while (right < s.length()) { char ch = s.charAt(right); window[ch]++; if (needs[ch] > 0 && needs[ch] >= window[ch]) { count++; } //移动到不满足条件为止 while (count == t.length()) { ch = s.charAt(left); if (needs[ch] > 0 && needs[ch] >= window[ch]) { count--; } if (right - left + 1 < minLength) { minLength = right - left + 1; res = s.substring(left, right + 1); } window[ch]--; left++; } right++; } return res; }
自己的代码:
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); } }
名企高频面试算法题解 文章被收录于专栏
牛客题霸 - 程序员面试高频题 - 题解