汇芳书院

专注计算机视觉、机器学习、分布式计算等领域, 兼聊投资、写作、生活

0%

76. 最小覆盖子串

给你一个字符串 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
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
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);
}
};
坚持原创分享,您的支持将鼓励我继续创作

欢迎关注我的其它发布渠道

------------- 本文结束,感谢阅读 如有问题可留言交流 -------------