题目
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), 我们很自然想到O(n)去扫描一遍字符串s
, 但是这就要求我们剩下的判断是否匹配要在O(1)的时间复杂度之内解决, 但是怎么在O(1)的时间内判断是否匹配呢?
我们可以这样做, 初始时total = t.length()
, 表示现在当前子串中我们还需要和t
进行匹配的字符数, 如果total = 0
, 此时说明当前子串和t
是匹配的, 更新答案即可。现在问题来了, 那么total
如何更新呢?
这里我们采用字母表进行数量检查更新total
, 具体操作如下:
- 初始化
int[] count = new int[256]
数组, 表示含义如:count[i]
表示t[i]
这个字符出现的次数, 即我们要进行匹配的个数。 - 我们使用双指针
i
和j
进行遍历,i
表示起始位置,j
表示结束位置, 扫描s
做以下判断。 - 如果
count[s[i]] > 0
此时说明,s[i]
这个字符恰好是我们要进行匹配的字符, 此时total
进行减1
操作, 接着count[s[i]]--
- 进行判断
total
, 如果此时total == 0
, 说明当前i -> j
这个子串已经是匹配成功的字符串了, 我们进行更新。 - 接下来判断
[count[s[i]]]
这个位置是不是= 0
, 因为下一步我们要开始移动i
指针了, 如果count[s[i]] == 0
说明这个是t
中要出现的字符, 如果移动i
指针的话, 我们必须要使得total++
。 - 接着我们要使
count[s[i]]++
, 原因很简单, 下一步i
指针要进行移动
代码实现
class Solution {
public String minWindow(String s, String t) {
char[] S = s.toCharArray();
char[] T = t.toCharArray();
int[] count = new int[256];
for (int i = 0; i < T.length; i++) count[T[i]]++;
/** from标记最终结果子串的起始位置, res表示最终结果的长度, total表示剩余匹配字符数*/
int from = 0, res = Integer.MAX_VALUE, total = T.length;
/** 使用双指针i, j, i表示子串起始位置, j表示字串结束位置*/
for (int i = 0, j = 0; j < S.length; j++) {
if (count[S[j]] > 0) total--;
count[S[j]]--;
/**此时, i->j已经是一个有效的匹配, 我们更新答案*/
while (total == 0) {
if (res > j - i + 1) {
res = j - i + 1;
/**更新最终答案起始位置*/
from = i;
}
/**如果该子串的其实位置是一个有效字符, 要移动i, 我们必须使total++*/
if (count[S[i]] == 0) total++;
/**更新*/
count[S[i]]++;
i++;
}
}
return res == Integer.MAX_VALUE ? "" : s.substring(from, from + res);
}
}
复制代码