1.最小覆盖子串
代码:
string minWindow(string s, string t) {
unordered_map<char, int> need, window;
for (char c : t) need[c]++;
int left = 0, right = 0;
int valid = 0;
// 记录最小覆盖子串的起始索引及长度
int start = 0, len = INT_MAX;
while (right < s.size()) {
// c 是将移入窗口的字符
char c = s[right];
// 右移窗口
right++;
// 进行窗口内数据的一系列更新
if (need.count(c)) {
window[c]++;
if (window[c] == need[c])
valid++;
}
// 判断左侧窗口是否要收缩
while (valid == need.size()) {
// 在这里更新最小覆盖子串
if (right - left < len) {
start = left;
len = right - left;
}
// d 是将移出窗口的字符
char d = s[left];
// 左移窗口
left++;
// 进行窗口内数据的一系列更新
if (need.count(d)) {
if (window[d] == need[d])
valid--;
window[d]--;
}
}
}
// 返回最小覆盖子串
return len == INT_MAX ?
"" : s.substr(start, len);
}
2.字符串排列
代码中要注意的点:
class Solution {
public:
bool checkInclusion(string s1, string s2) {
unordered_map<char,int> need,window;
int right=0,left=0;
int valid=0;
for(auto s:s1){
need[s]++;
}
while(right<s2.size()){
char c=s2[right];
right++;
if(need.count(c)){
window[c]++;
if(window[c]==need[c])
valid++;
}
//窗口收缩的条件要具体考虑,如最小覆盖子串的收缩条件是valid == need.size(),因为他要寻找的是最小
//子串,而当搜索条件满足时,表明当前窗口内包含了字符串T中的全部字符。且窗口内所需的字符是可以
//不连续的
//而这道题与上题不同,right-left>=s1.size()保证了当窗口大小等于s1字符串大小时,就会检测窗口内的 字
//符是否是s1字符的排列,这样能实现检测出的满足要求的子串一定是连续的,这也和上一题形成对比,上
//一题的满足收缩要求的窗口内需要集齐的字符不要求是连续的。
//综上,需要集齐的字符要求是连续的,则收缩条件为right-left>=s1.size()
while(right-left>=s1.size()){
if(valid==need.size()) //一定注意是等于need.size
return true;
char d=s2[left];
left++;
if(need.count(d)){
if(window[d]==need[d])
valid--;
window[d]--;
//注意上面的window[c]++是跟在if(need.count(c))后面的,而这里的window[d]--一定是在最后的,
//因为window[c]++是先记录进入窗口的字符,再判断该字符是否已经满足了需要的数量
//而window[d]--如果跟在if(need.count(d))后面,就会出现在进行 if(window[d]==need[d])判断前,
//window[d]已经发生改变了,因此他是先进行 if(window[d]==need[d])判断,再进行window[d]--操作。
}
}
}
return false;
}
};
3.无重复字符的最长子串
代码:
class Solution {
public:
int lengthOfLongestSubstring(string s) {
unordered_map<char,int> window;
int right=0,left=0,maxlen=0;
while(right<s.size()){
char c=s[right];
right++;
window[c]++;
while(window[c]>1){
maxlen=(right-left-1)>maxlen?(right-left-1):maxlen; //刚开始最大长度错误地放在窗口缩小时更新,
//但这样就无法准确处理长度为1的字符串了,因为此时不会满足窗口缩小的条件,也就无法更新maxlen
char d=s[left];
left++;
window[d]--;
}
maxlen=(right-left-1)>maxlen?(right-left-1):maxlen;//因此上方的maxlen更新应该删掉,改到这里
}
return maxlen;
}
};