难度: 困难
题目
给你一个字符串 s
、一个字符串 t
。返回 s
中涵盖 t
所有字符的最小子串。如果 s
中不存在涵盖 t
所有字符的子串,则返回空字符串 ""
。
注意: 如果 s
中存在这样的子串,我们保证它是唯一的答案。
示例
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
解题思路
这⼀题是滑动窗⼝的题⽬,在窗⼝滑动的过程中不断的包含字符串 t
,直到完全包含字符串 t
的字符以后,起始位置向后移动至刚好不再完全包含字符串t
时,记下左侧窗口的位置减一,和减一后的窗⼝⼤⼩。每次都不断更新这个符合条件的窗⼝和窗⼝⼤⼩的最⼩值。最后输出结果即可。
本题难点在于如何判断已经完全包含字符串t
。这里我使用HashMap,扫描字符串t
时,每个字符作为key,value是其次数。扫描字符串s
时,每扫描到一次HashMap内包含的字符时便使其value减一,当HashMap内的value全部不大于0时,滑动窗口便完全覆盖了字符串t
。
代码
class Solution {
public String minWindow(String s, String t) {
HashMap<Character, Integer> map = new HashMap<Character, Integer>();
int minStart = 0, start = 0;
int len = s.length();
int minLen = len + 1;
// 初始化map
for(int i=0; i<t.length(); i++) {
char c = t.charAt(i);
if(map.get(c) == null) {
map.put(c,1);
} else {
map.put(c, map.get(c) + 1);
}
}
for(int end = 0; end < len; end++) {
char key = s.charAt(end);
// 更新map
if(map.get(key) != null) map.put(key, map.get(key) - 1);
if(check(map)) { // 已经完全包含
while(check(map)) { // 直到不再完全包含为止
char c = s.charAt(start);
if(map.get(c) != null) {
map.put(c, map.get(c) + 1);
}
start++;
}
if((end - start + 2) < minLen) {
minLen = end - start + 2;
minStart = start - 1;
}
}
}
// 判断是否找到最小覆盖子串并返回结果
if (minLen != len + 1) {
return s.substring(minStart, minStart + minLen);
} else {
return "";
}
}
// 检查是否已经完全包含
public boolean check(HashMap map) {
for(Object key : map.keySet()) {
if((int)map.get(key) > 0) {
return false;
}
}
return true;
}
}