最小覆盖子串
给你一个字符串 S、一个字符串 T 。请你设计一种算法,可以在 O(n) 的时间复杂度内,从字符串 S 里面找出:包含 T 所有字符的最小子串。
示例:
输入:S = “ADOBECODEBANC”, T = “ABC”
输出:“BANC”
class Solution {
public:
string minWindow(string s, string t) {
map<char,int> st;
int needNum=t.size();
char c;
for(char c:t){
if(st.count(c)==0){
st[c]=0;
}
st[c]+=1;
}
int left=0;
int right=100000000;
int i=0;
for(int j=0;j<s.size();j++){
c=s[j];
if(st.count(c)==0){
st[c]=0;
}else if(st[c]>0){
needNum-=1;
}
st[c]-=1;
if(needNum==0){
while(i<=j){
if(st[s[i]]==0){
break;
}
st[s[i]]+=1;
i+=1;
}
if((j-i)<(right-left)){
left=i;
right=j;
}
needNum+=1;
st[s[i]]+=1;
i+=1;
}
}
if(right==100000000){
return "";
}
return s.substr(left,right-left+1);
}
};
字符串的排列
给定两个字符串 s1 和 s2,写一个函数来判断 s2 是否包含 s1 的排列。
换句话说,第一个字符串的排列之一是第二个字符串的子串。
class Solution {
public:
bool checkInclusion(string s1, string s2) {
map<char,int> init_map;
map<char,int> cur_map;
int len=s2.size();
int init_needNum=0;
int cur_needNum=0;
for(char c:s1){
if(init_map.count(c)==0){
init_map[c]=0;
}
init_map[c]+=1;
init_needNum+=1;
}
cur_needNum=init_needNum;
cur_map=map<char,int>(init_map);
int i=0;
for(int j=0;j<len;j++){
// for(auto k:cur_map){
// cout<<k.first<<cur_map[k.first];
// }
// cout<<endl;
char c=s2[j];
if(cur_map.count(c)>0){
if(cur_map[c]>0){
cur_needNum-=1;
if(cur_needNum==0){
return true;
}
cur_map[c]-=1;
}else{
while(i<=j){
char t=s2[i];
cur_needNum+=1;
cur_map[t]+=1;
if(t==c){
i=i+1;
break;
}
i=i+1;
}
cur_needNum-=1;
cur_map[c]-=1;
}
}else{
cur_needNum=init_needNum;
cur_map=map<char,int>(init_map);
i=j+1;
if(i==(len-1)){
return false;
}
}
}
return false;
}
};
简化版本
class Solution {
public:
bool checkInclusion(string s1, string s2) {
unordered_map<char, int> mp;
for (auto &c: s1) mp[c]++; // 记录 出现次数的差值
int l = 0, r = 0;
while (r < s2.size()){
char c = s2[r++];
mp[c]--; // 入窗
while (l < r && mp[c] < 0){ // 出窗
mp[s2[l++]] ++;
}
if (r - l == s1.size()) return true;
}
return false;
}
};
KMP
为了描述状态转移图,我们定义一个二维 dp 数组,它的含义如下:
dp[j][c] = next
0 <= j < M,代表当前的状态
0 <= c < 256,代表遇到的字符(ASCII 码)
0 <= next <= M,代表下一个状态
dp[4][‘A’] = 3 表示:
当前是状态 4,如果遇到字符 A,
pat 应该转移到状态 3
dp[1][‘B’] = 2 表示:
当前是状态 1,如果遇到字符 B,
pat 应该转移到状态 2
class Solution {
public:
void KMP(vector<vector<int>> & dp , string & pat) {
int len=pat.size();
int x=0;
dp[0][int(pat.at(0))]=1;
for(int i=1;i<len;i++){
for(int j=0;j<256;j++){
if(j==int(pat.at(i))){
dp[i][j]=i+1;
}else{
dp[i][j]=dp[x][j];
}
}
x=dp[x][int(pat.at(i))];
}
return;
}
int strStr(string haystack, string needle) {
int len_n=needle.size();
int len_h=haystack.size();
if(len_n==0){
return 0;
}
if(len_h==0){
return -1;
}
int cur_state=0;
vector<vector<int>> dp(len_n,vector<int>(256,0));
KMP(dp,needle);
for(int i=0;i<len_h;i++){
cur_state=dp[cur_state][haystack.at(i)];
// cout<<cur_state<<endl;
if(cur_state==len_n){
return i-len_n+1;
}
}
return -1;
}
};