Problem: 76. 最小覆盖子串
文章目录
- 思路
- 相似滑动窗口题目 :
- Code
题目
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。
示例 1:
输入:s = “ADOBECODEBANC”, t = “ABC”
输出:“BANC”
解释:最小覆盖子串 “BANC” 包含来自字符串 t 的 ‘A’、‘B’ 和 ‘C’。
示例 2:
输入:s = “a”, t = “a”
输出:“a”
解释:整个字符串 s 是最小覆盖子串。
示例 3:
输入: s = “a”, t = “aa”
输出: “”
解释: t 中两个字符 ‘a’ 均应包含在 s 的子串中,
因此没有符合条件的子字符串,返回空字符串。
思路
思路就是维护一个滑动窗口,窗口
[left,right]
,每次让right右端点右滑动,如果滑动到的字符是t串里面的,就让一个num(记录当前窗口中所包含的t中字符的个数)记录下,当num = t中字符个数,就开始收缩窗口,收缩窗口是从左边left收缩(left++),当收缩到的字符在t中存在,num–。
Note :
如果在每次开始收缩时记录当前的字符串,在266数据会卡内存,所以要改成记录子串的起始start,通过substr(start,len),获取最小子串。
相似滑动窗口题目 :
Code
class Solution {
public:
string minWindow(string s, string t) {
string ans = "" ;
int n = s.size() ;
int left = 0 , right = 0 ;
int min_length = 10e5+1 ;
int start = 0 ;
int num = 0 ; // 记录当前窗口中所包含的t的字符个数
unordered_map<char,int> window ;
unordered_map<char,int> smap ;
// 先计算出t串中的字符次数
for(char v : t) {
smap[v]++ ;
}
while(right <n){
char ch = s[right] ;
// 右移动
right++ ;
if(smap.count(ch)){
window[ch]++ ;
if(window[ch] == smap[ch]){
num++ ; // 包含数+1
}
}
//当全部包含在内时
while(num == smap.size()) {
int cur_length = right-left ;
if(cur_length < min_length){
min_length = cur_length ;
start = left ;
// 直接记录ans 会卡内存
// ans = s.substr(left,min_length) ;
}
char d = s[left] ;
left++ ;
if(smap.count(d)){
if(window[d] == smap[d]) {
num-- ; // 如果要去掉的是包含的
}
//收缩左边端点
window[d]-- ;
}
}
}
if(min_length == 10e5+1) return "" ;
return s.substr(start,min_length) ;
}
};