leetcode刷题记之76 Minimum Window Substring

@author stormma
@date 2018/04/10


生命不息,奋斗不止

题目

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,

1
2
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, 具体操作如下:

  1. 初始化int[] count = new int[256]数组, 表示含义如: count[i]表示t[i]这个字符出现的次数, 即我们要进行匹配的个数。
  2. 我们使用双指针ij进行遍历, i表示起始位置, j表示结束位置, 扫描s做以下判断。
  3. 如果count[s[i]] > 0此时说明, s[i]这个字符恰好是我们要进行匹配的字符, 此时total进行减1操作, 接着count[s[i]]--
  4. 进行判断total, 如果此时total == 0, 说明当前i -> j这个子串已经是匹配成功的字符串了, 我们进行更新。
  5. 接下来判断[count[s[i]]]这个位置是不是= 0, 因为下一步我们要开始移动i指针了, 如果count[s[i]] == 0说明这个是t中要出现的字符, 如果移动i指针的话, 我们必须要使得total++
  6. 接着我们要使count[s[i]]++, 原因很简单, 下一步i指针要进行移动

代码实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
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);
}
}