双指针
双指针就是两个指针,分别指向数组或者字符串的首端或者尾端
前言
早成者未必有成,晚达者未必不达!
一、最小覆盖子串
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
- 对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
- 如果 s 中存在这样的子串,我们保证它是唯一的答案。
统计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;//INT_MAX表示21亿
主程序
while(right<s.size()){
//c是移入窗口的字符
char c=s[right];
//右边窗口加1
right++;
if(need.count(c)){//如果c字符在t中
window[c]++;//窗口中c字符加1
if(window[c]==need[c])//如果c字符与t中的相等,则valid加1,证明t中该字符够了,
valid++;
}
//字符种类够到了一定程度,则说明当前窗口覆盖了t
while(valid==need.size()){
//记录下最小覆盖子串两边位置
if(right-left<len){
start=left;
len=right-left;
}
char d=s[left];
left++;//左窗口移动,不用怕这会变成不符合的情况,符合的情况已经被记录下来了,无所谓
if(need.count(d)){
if(window[d]==need[d])
valid--;
window[d]--;
}
}
//如果len==INT_MAX,说明啥也没找到,返回空
return len==INT_MAX?"":s.substr(start,len);//substr函数,截取字符串,左闭右开
完整代码
class Solution {
public:
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;
}
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);
}
};
二、找到字符串中所有字母异位词
给定两个字符串 s 和 p,找到 s 中所有 p 的 异位词 的子串,返回这些子串的起始索引。不考虑答案输出的顺序。
异位词 指由相同字母重排列形成的字符串(包括相同的字符串)。
代码
跟上面基本一样
class Solution {
public:
vector<int> findAnagrams(string s2, string s1) {
unordered_map<char,int>n,w;
for(char &i:s1)n[i]++;
int l=0,r=0,v=0;
vector<int>res;
while(r<s2.size()){
char c=s2[r];
r++;
if(n.count(c)){
w[c]++;
if(w[c]==n[c])
v++;
}
while(r-l>=s1.size()){
if(v==n.size()){
res.push_back(l);
}
char d=s2[l];
l++;
if(n.count(d)){
if(w[d]==n[d])
v--;
w[d]--;
}
}
}
return res;
}
};
总结
双指针不难,都有模板的,加油吧,慢慢学