题目:
给你一个字符串 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 的子串中, 因此没有符合条件的子字符串,返回空字符串。
提示:
1 <= s.length, t.length <= 105
s
和t
由英文字母组成
代码:
# 滑动窗口法
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char,int> hs, ht;
for (int i = 0; i < t.size(); ++i) ht[t[i]]++; // 统计字符串t的个数
string ans; // 最终的结果
int left = 0; // 窗口左边界
int counter = 0; // 计数
for (int right = 0; right < s.size(); right++) { // 右边界无脑向右移动
hs[s[right]]++; // 右边界元素在哈希表中个数+1
if (hs[s[right]] <= ht[s[right]]) { // 如果右边界元素在s哈希表中的个数<=在t中的个数,s哈希表该元素的个数+1
counter++;
}
while (hs[s[left]] > ht[s[left]]){ // 左边界元素在s哈希表中的个数>在t中的个数,说明窗口该缩小了,i向右移动,同时元素在s哈希表个数-1
hs[s[left]]--;
left++;
}
// 经过上面的一段操作,如果计数为t的长度,说明,窗口内将将好包含t,再和之前的ans长度作比较,当目前窗口大小小于ans,给ans做更新。
if (counter == t.size()) {
if (ans.empty() || ans.size() > (right-left+1))
ans = s.substr(left,right-left+1);
}
}
return ans;
}
};
关键思路:
- 借用的是力扣@vincent的代码。
- 滑动窗口法,右边界就是无脑向右移动,本题中,每次右边界移动,都判断一下左边界和右边界的情况。右边界:如果s的哈希表中个数小于等于t哈希表,计数器+1;左边界,s哈希>t哈希的话,缩小窗口,left+1,且一直判断,直到left处在哈希表中满足条件。然后再看计数器是否=t的长度,如果是,那么此时窗口中刚好包含t,比较之前的结果,更新ans。