一、题目

给你一个字符串 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 由英文字母组成

二、思路
  • 使用滑动窗口求解。窗口大小为【l,r】里面包含的字符要满足题中所给的条件。使用cnts数组来保存t字符串中每个字母出现的个数。然后遍历s字符串,若当前字母的个数–cnts[s[r]] >= 0代表有字母满足在t中,那么字母总存在数+1,当总存在数=t的长度,代表这个窗口中已经包含t的所有字母,这个时候l向右移动至最小满足条件的位置,保存最小长度min_len和开始的所有min_l。
三、代码

class Solution {
public:
string minWindow(string s, string t) {
vector<int> cnts(128, 0); //这个字母在t中出现的次数
int m = s.length(), n = t.length(), cnt = 0, l = 0, r = 0, min_l = 0, min_len = 1e6;
for (int i = 0; i < n; i++) {
cnts[t[i]]++;
}
//[l, r]为滑动窗口的位置
for (r = 0; r < m; r++) {
//如果这个字符在t中个数减少
if (--cnts[s[r]] >= 0) {
cnt++; //代表已经有多少个字符存在了 当有n个字符代表满足条件
}
//移动l到最小满足条件的范围
while (cnt == n) {
//更新满足条件的最小长度
if (r - l + 1 < min_len) {
min_len = r - l + 1;
min_l = l;
}
//如果l位置的字符在t中且去除后窗口不全包含t时cnt--
if (++cnts[s[l]] > 0) cnt--;
l++;
}
}
return min_len == 1e6 ? "":s.substr(min_l, min_len);
}
};