[LeetCode] 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).
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.
首先建立两个HashMap或Array(int),初始256个字符出现的次数都为0,一个TMap用来统计T中所有字母的个数,另一个SMap用来统计S中出现的T中含有的字母个数。使用双指针来动态维护一个窗口区间,尾指针不断向后扫,当扫到的字符在TMap中存在,说明找到了一个字符,把它添加到SMap中。当有一个窗口包含了所有T的字符后,就收缩头指针,直到保证窗口包含T中字母不能再收缩为止,比较这个窗口,记录所有可能的情况中窗口最小的。
因为ASCII字符数量只有256个,所以HashMap可以用数组来代替,比如字符串"aabb",array[97] = 2,array[98] = 2。
Java:
public class Solution { public String minWindow(String S, String T) { int[] srcHash = new int[256]; for(int i = 0; i < T.length(); i++){ srcHash[T.charAt(i)]++; } int start = 0,i= 0; int[] destHash = new int[256]; int found = 0; int begin = -1, end = S.length(), minLength = S.length(); for(start = i = 0; i < S.length(); i++){ 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++; } } return begin == -1 ? "" : S.substring(begin,end + 1); } }
Python:
class Solution(object): def minWindow(self, s, t): """ :type s: str :type t: str :rtype: str """ current_count = [0 for i in xrange(256)] expected_count = [0 for i in xrange(256)] for char in t: expected_count[ord(char) - ord('a')] += 1 i, count, start, min_width, min_start = 0, 0, 0, float("inf"), 0 while i < len(s): current_count[ord(s[i]) - ord('a')] += 1 if current_count[ord(s[i]) - ord('a')] <= expected_count[ord(s[i]) - ord('a')]: count += 1 if count == len(t): while expected_count[ord(s[start]) - ord('a')] == 0 or \ current_count[ord(s[start]) - ord('a')] > expected_count[ord(s[start]) - ord('a')]: current_count[ord(s[start]) - ord('a')] -= 1 start += 1 if min_width > i - start + 1: min_width = i - start + 1 min_start = start i += 1 if min_width == float("inf"): return "" return s[min_start:min_start + min_width]
C++:
class Solution { public: string minWindow(string S, string T) { if(S.empty() || S.size() < T.size()) return ""; int appeared_count[256] = {0}; int expected_count[256] = {0}; for(int i = 0 ; i < T.size() ; i++) expected_count[T[i]]++; int minWidth = INT_MAX , min_start = 0; int wnd_start = 0; int appeared = 0; //appeared记录S中出现的T中的字符的个数,当appeared==T.size()时,说明找到一个符合条件的 for(int wnd_end = 0 ; wnd_end < S.size() ; wnd_end++) { if(expected_count[S[wnd_end]] > 0) { appeared_count[S[wnd_end]]++; if(appeared_count[S[wnd_end]] <= expected_count[S[wnd_end]]) appeared++; //当字符S[wnd_end]出现的次数不大于T中出现次数时,appeared才++ } if(appeared == T.size()) { while(appeared_count[S[wnd_start]] > expected_count[S[wnd_start]] || expected_count[S[wnd_start]] == 0) { appeared_count[S[wnd_start]]--; wnd_start++; } if(minWidth > (wnd_end - wnd_start + 1)) { minWidth = wnd_end - wnd_start + 1; min_start = wnd_start; } } } if(minWidth == INT_MAX) return ""; else return S.substr(min_start , minWidth); } };
类似题目:
[LeetCode] 3.Longest Substring Without Repeating Characters 最长无重复子串
[LeetCode] 159. Longest Substring with At Most Two Distinct Characters 最多有两个不同字符的最长子串
[LeetCode] 340. Longest Substring with At Most K Distinct Characters 最多有K个不同字符的最长子串
[LeetCode] 727. Minimum Window Subsequence 最小窗口子序列