本文参照添加链接描述
题目描述
给你一个字符串 S、一个字符串 T,请在字符串 S 里面找出:包含 T 所有字符的最小子串。
示例:
输入: S = “ADOBECODEBANC”, T = “ABC”
输出: “BANC”
说明:
如果 S 中不存这样的子串,则返回空字符串 “”。
如果 S 中存在这样的子串,我们保证它是唯一的答案。
题目分析
1、我们在字符串 S 中使用双指针中的左右指针技巧,初始化 left = right = 0,把索引左闭右开区间 [left, right) 称为一个「窗口」。
2、我们先不断地增加 right 指针扩大窗口 [left, right),直到窗口中的字符串符合要求(包含了 T 中的所有字符)。
3、此时,我们停止增加 right,转而不断增加 left 指针缩小窗口 [left, right),直到窗口中的字符串不再符合要求(不包含 T 中的所有字符了)。同时,每次增加 left,我们都要更新一轮结果。
4、重复第 2 和第 3 步,直到 right 到达字符串 S 的尽头。
初始状态
增加right,直至数组【left,right】包含所有T
然后开始增加left,缩小【left,right】
直至不满足条件,left不在移动。之后重复上述过程,先移动 right,再移动 left…… 直到 right 指针到达字符串 S 的末端,算法结束。
class Solution {
public:
string minWindow(string s, string t) {
map<char,int>res;
map<char,int>path;
for( char c:t){
path[c]++;
}
//count记录字符串s中包含字符串T的树数目
int left=0,right=0,count=0;
int len=INT_MAX,start=0;
while(right<s.length()){
// c 是将移入窗口的字符
char c=s[right];
res[c]++;
//右移窗口
right++;
//更新新的窗口(即判断字符串s中的字符在t中是否存在)
if(path.count(c)&&res[c]==path[c]){
count++;
}
// 判断左侧窗口是否要收缩
while(count==t.length()){
//更新窗口范围
if(right-left<len){
len=right-left;
start=left;
}
//字符d是将要移出窗口的字符
char d=s[left];
left++;
res[d]--;
if(path.count(d)&&res[d]==path[d]){
count--;
}
}
}
//返回最小覆盖子串
return len==INT_MAX?"":s.substr(start,len) ;
}
};
但是本人写的好像出现点bug,大神们自己找找吧!累了(找到了也告诉我一下。。。)
另一种算法结构是参考B站大神思路双指针算法
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<string>
#include<unordered_map>
using namespace std;
const int N = 100000;
int a[N + 5];
int main()
{
string s = "CdAAArBCDRNDAFRED";
string t = "BAN";
string res;
unordered_map<char, int>hash;
for (auto c : t)hash[c]++;
int c = t.length();
for (int i = 0, j = 0, cnt = 0; i < s.length(); i++) {
if (hash[s[i]] == 1) {
cnt++;
}
hash[s[i]]--;
while(hash[s[j]] < 0)hash[s[j++]]++;//即当前字符哈希表内存储的数据小于0时,滑动数组向前移动
if (c == cnt) {
if (res.empty() || res.size() > i - j + 1)res = s.substr(j,i-j+1);
}
}
cout << res;
return 0;
}