题目来源:https://leetcode-cn.com/problems/minimum-window-substring/
大致题意:
给一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
思路
使用滑动窗口表示满足题意的 s 的子串
- 先使用哈希表存 t 所有字符以及对应个数
- 初始时,窗口只包括 s 的首字符,然后开始在 s 上移动窗口,并在移动过程中使用哈希表存下 t 中字符在窗口中的对应个数
- 每次移动后,都检查当前窗口右边界对应的字符是否在字符串 t 中,若在,则更新哈希表
- 然后检查目前窗口是否包含 t 中所有字符,若已经包含,更新最小窗口。之后右移左边界,缩小窗口。重复这个过程,直至当前窗口不包含 t 中所有字符
代码:
public class MinWindow {
Map<Character, Integer> charMap; // 存 t 中字符以及对应个数
Map<Character, Integer> windowMap; // 存窗口中字符以及对应个数
public String minWindow(String s, String t) {
charMap = new HashMap<>();
windowMap = new HashMap<>();
// 统计 t 中字符以及对应个数
for (int i = 0; i < t.length(); i++) {
char c = t.charAt(i);
charMap.put(c, charMap.getOrDefault(c, 0) + 1);
}
// 窗口左右边界
int l = 0;
int r = 0;
// 窗口最小长度
int ans = Integer.MAX_VALUE;
// 最小窗口对应索引
int ansL = 0;
int ansR = 0;
int n = s.length();
// 若右边界未越界,则继续
while (r < n) {
char c = s.charAt(r);
// 若 t 包含当前字符,更新窗口对应哈希表
if (charMap.containsKey(c)) {
windowMap.put(c, windowMap.getOrDefault(c, 0) + 1);
}
// 若窗口中包含 t 的所有字符,且长度大于 0
while (check() && l <= r) {
// 更新最小窗口
int len = r - l + 1;
if (ans > len) {
ans = len;
ansL = l;
ansR = r + 1;
}
// 左边界右移,更新哈希表
windowMap.put(s.charAt(l), windowMap.getOrDefault(s.charAt(l), 0) - 1);
l++;
}
// 右边界右移
r++;
}
return s.substring(ansL, ansR);
}
// 判断窗口是否包含 t 中所有字符
public boolean check() {
for (Map.Entry<Character, Integer> entry : charMap.entrySet()) {
char c = entry.getKey();
int count = entry.getValue();
if (count > windowMap.getOrDefault(c, 0)) {
return false;
}
}
return true;
}
}