Time:2020/12/18
week6 滑动窗口,双指针,单调队列,单调栈
LeetCode 76 最小覆盖子串 (Hard)
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。注意:如果 s 中存在这样的子串,我们保证它是唯一的答案。
输入:s = "ADOBECODEBANC", t = "ABC"
输出:"BANC"
输入:s = "a", t = "a"
输出:"a"
提示:
-
1 <= s.length, t.length <= 105
-
s
和t
由英文字母组成
思路分析:
本题目中可使用双指针算法。定义双指针分别为i, j。其中i为后面的指针,j为前面的指针。i与j之间的部分就是我们所截取的字符串子串,其长度为i-j+1,。可以表示为subs1=s.substring(j,i-j+1);
关键点1:如果一旦在j与i之间搜索的字符子串已经满足我们的要求,那么当i指针执行**i++**继续向后移动的时候,j指针只有两种可能(原地不动,或者向后移动)。这是因为我们需要找的是满足条件的最短字符子串。
关键点2:如何判断当前子串subs1中是否已经包含t中所有的字符**?** 我们借助于数据结构hash表。unordered_maphash,其key是t中所出现的字符,value为出现字符的次数。并且记录下hash的尺寸cnt。int cnt = hash.size();
程序解读:
step1:定义结果字符串res
step2:进入for循环,指针i往后移动。其中c的意义是当前满足条件的字符的个数。
如果hash[s[i]]==1,则意味着s[i]是t中出现过的字符,且只出现过一次,此时当前满足条件的字符个数c++。
如果hash[s[i]] >1,则意味着s[i]是t中出现过的字符,且不止出现过一次。
*step3:*执行hash[s[i]]– 。如果s[i]不是t中出现的字符,那么其对应的value将为负数。
*step4:*当hash[s[j]]<0 的时候,意味着当前范围的子串起点字符不是t中的元素,所以j向后移,执行j++。并且更新hash[s[j++]]++。
*step5:*如果c==cnt,则说明当前子串已经包含了t中所有字符,判断长度并且更新res即可。
class Solution {
public:
string minWindow(string s, string t) {
unordered_map<char, int> hash;
for(auto c :t)
hash[c]++;
int cnt = hash.size();
string res;
for(int i = 0, j = 0 ,c = 0; i < s.size();i++ )
{
if(hash[s[i]]==1)
c++;
hash[s[i]]--;
while(hash[s[j]] < 0)
hash[s[j++]]++;
if(c == cnt )
if(res.empty() || res.size() >i-j+1)
res = s.substr(j,i-j+1);
}
return res;
}
};