76. 最小覆盖子串
· 约 2 分钟阅读 · – 次阅读
leetcode
给你一个字符串 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 的子串中, 因此没有符合条件的子字符串,返回空字符串。
双指针方案
核心问题是判断窗口内的子串是否覆盖了目标串。
class Solution {
unordered_map<char, int> mapT, mapS;
public:
string minWindow(string s, string t) {
int sLen = s.size();
int tLen = t.size();
if (sLen == 0 || tLen == 0 || sLen < tLen) {
return "";
}
for (auto c : t) {
++mapT[c];
}
int begin=0,count=sLen+1;
int left = 0, right = 0;
// distance记录滑动窗口内部包含的t中的元素的个数, 若窗口中某个字符个数超过t中该元素的个数,distance不增加
int distance = 0;
// [left, right)
while (right < sLen) {
// 右指针右移,如果字符不在t中,则指针继续右移,直到碰到t中的字符。
if (mapT[s[right]] == 0) {
right++;
continue;
}
// 如果这个字符在滑动窗口内的个数小于需要的个数,则表明此时右移对结果有帮助,distance加1
if (mapS[s[right]] < mapT[s[right]]) {
distance++;
}
// 更新窗口中字符的个数,然后右指针继续右移
++mapS[s[right]];
right++;
// 当distance和t的长度一致,说明碰到了一个可能的解
while (distance == tLen) {
// 判断是否是最优解并更新
if (right-left < count) {
begin = left;
count = right-left;
}
//如果左指针对应字符不是需要的元素,则指针右移
if (mapT[s[left]] == 0) {
left++;
continue;
}
// 左指针右移的时候,窗口中字符个数在减少,当字符为需要字符且个数不多时,左指针继续右移会让距离减1
if (mapS[s[left]] == mapT[s[left]]) {
distance--;
}
--mapS[s[left]];
left++;
}
}
// cout << begin << " " << count;
// 若count未更新
if (count == sLen+1) {
return "";
}
return s.substr(begin, count);
}
};