给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
示例 2:
输入:s = "a", t = "a"
输出:"a"
示例 3:
输入: s = "a", t = "aa"
输出: ""
解释: t 中两个字符 'a' 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。
思路
在这道题中, 我们采用滑动窗口的思路来解题.
初始化 [left, right)的窗口window, 不断增加 right指针 扩大窗口范围, 直至窗口中的元素满足要求.
此时, 我们停止增大 right指针, 转而增大 left指针 来不断缩小窗口范围, 直至窗口中的元素不再满足要求, 每增加一次 left指针, 我们便要更新一轮结果.
重复以上思路, 直至 right 到达字符串尽头.
我们采用 need 来记录目标字符串中字符出现的次数, 使用 valid 来记录 window 中满足 need 条件的字符个数, 如果 valid等于need.size(), 开始收缩窗口范围.
代码
class Solution {
public:
string minWindow(string s, string t) {
map<char, int> need, window;
for (char c : t) {
need[c]++;
}
int valid = 0;
int left = 0, right = 0;
int start = 0, length = INT_MAX;
while (right < s.length()) {
char c = s[right];
right++;
/*
在这里有一个问题:
当 key = c 时, 那他对应的 value 应该是大于等于 1 的;
但是 need[c] >= 1 的判定条件无法求的结果, 只能使用
need.find(c) != need.end() 或 need.count(c)
解决:
如果使用 need[c] >= 1, 当 c 不存在的时候,
need 会在创建一个新的索引, 导致 need.size() 越来越大
*/
if (need.find(c) != need.end()) {
window[c]++;
if (window[c] == need[c])
valid++;
}
while (valid == need.size()) {
if (right - left < length) {
start = left;
length = right - left;
}
char ch = s[left];
left++;
if (need.find(ch) != need.end()) {
if (window[ch] == need[ch])
valid--;
window[ch]--;
}
}
}
return length == INT_MAX ? "" : s.substr(start, length);
}
};