32. 最小子串覆盖
描述
给定两个字符串 source
和 target
. 求 source
中最短的包含 target
中每一个字符的子串.
- 如果没有答案, 返回
""
. - 保证答案是唯一的.
target
可能包含重复的字符, 而你的答案需要包含至少相同数量的该字符.
样例
样例 1:
输入: source = "abc", target = "ac"
输出: "abc"
样例 2:
输入: source = "adobecodebanc", target = "abc"
输出: "banc"
解释: "banc" 是 source 的包含 target 的每一个字符的最短的子串.
样例 3:
输入: source = "abc", target = "aa"
输出: ""
解释: 没有子串包含两个 'a'.
挑战
O(n) 时间复杂度
题解:
class Solution {
public:
/**
* @param source : A string
* @param target: A string
* @return: A string denote the minimum window, return "" if there is no such a string
*/
string minWindow(string &source , string &target) {
// 初始化counter_s和counter_t
unordered_map<char, int> counter_t, counter_s;
for (char c : target) {
counter_t[c]++;
}
int left = 0, valid = 0;
// 记录最小覆盖子串的起始索引及长度
int start = -1, minlen = INT_MAX;
for (int right = 0; right < source.size(); right ++){
// 移动右边界, ch 是将移入窗口的字符
char ch = source[right];
if (counter_t.count(ch)) {
counter_s[ch]++;
if (counter_s[ch] == counter_t[ch])
valid++;
}
// 判断左侧窗口是否要收缩
while (valid == counter_t.size()) {
// 更新最小覆盖子串
if (right - left < minlen) {
start = left;
minlen = right - left;
}
// left_ch 是将移出窗口的字符
char left_ch = source[left];
// 左移窗口
left ++;
// 进行窗口内数据的一系列更新
if (counter_t.count(left_ch)) {
if (counter_s[left_ch] == counter_t[left_ch])
valid--;
counter_s[left_ch] --;
}
}
}
// 返回最小覆盖子串
return start == -1 ? "" : source.substr(start, minlen + 1);
}
};