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.
这道题目的思路跟 找到链接所有单词的子串有些类似,我们容易得到一个时间复杂度为O( n^2 )的解法。
我们用start和end来标记子串的开始和结束,每次从start index = 0开始,找到合法的子字符串。
但我们要意识到:
如果S = "aabc", T = "abc"
当start = 0 的时候,我们可以得到end = 3,此时的子串长度为4
当start = 1的是时候,其实我们没有必要再次进行计算了,start = 1也是符合要求的子串。
所以,我们的思路转变成了:
1. 从start开始,先找到一个合法的子串
2. 在这个子串中寻找有没有更小的子串
这样可以避免大量重复的计算。
再以S = "ebadbaccb", T = "abc"为例。
当start = 0的时候,我们可以得到end = 6。我们得到了一个合法的子串。
之后寻找更小的子串,对于不在"abc"中 (比如s [ 0 ] ) 和多余的字符(比如s [ 2 ] ), 我们都可以舍弃掉,最后start = 4。我们得到了当前最小的length = 3的子串。
之后start ++ , end还是在6,此时"b"是缺省的,继续往后找,有可以得到end = 8, start = 5, 此时的子串长度为5。
所以,最小的长度为3。
算法的时间复杂度为O ( n )。
运行时间:
代码:
public class MinimumWindowSubstring {
public String minWindow(String s, String t) {
int[] count = new int[128];
for (int i = 0; i < t.length(); i++) {
count[t.charAt(i)]++;
}
int start = 0, i = 0, countNum = t.length();
int minBegin = -1;
int minLen = Integer.MAX_VALUE;
while (i < s.length() - countNum + 1) {
if (count[s.charAt(i)] > 0) {
countNum--;
}
count[s.charAt(i)]--;
i++;
while (countNum == 0) { // avoid some repeat
if (i - start < minLen) {
minLen = i - start;
minBegin = start;
}
count[s.charAt(start)]++;
// when char exists in t, increase counter.
if (count[s.charAt(start)] > 0) {
countNum++;
}
start++;
}
}
return minBegin == -1 ? "" : s.substring(minBegin, minBegin + minLen);
}
}