拼接字符串法
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0);cout.tie(0);cin.tie(0);
#define endl '\n'
#define int long long
const int N=2e6+114;
void build_border(string str,vector<int>& border){//数组从0开始计数
int str_len=str.length();
border[0]=0;
for(int i=1;i<str_len;i++){
int j=border[i-1];
while(j>0 && str[j]!=str[i])j=1+border[j-1]-1;//转到第二长的可匹配前缀
//-1是因为字符串从0开始,border[j-1]长度-1才是正确的位置 ,+1是因为要暴力扩展是否匹配
if(str[j]==str[i])j++;
border[i]=j;
}
return;
}
signed main(){
IOS
string s1,s2;
cin>>s1>>s2;
int len2=s2.length();
string str=s2+"#"+s1;
int len=str.length();
vector<int>border(len);
build_border(str,border);
for(int i=len2*2-1;i<len;i++){
if(border[i]==len2)cout<<i-2*len2+1<<endl;
}
vector<int> border2(len2);
build_border(s2,border2);
for(int i=0;i<len2;i++){
cout<<border2[i]<<" ";
}
return 0;
}
双指针滑动法
#include<bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0);cout.tie(0);cin.tie(0);
#define endl '\n'
#define int long long
const int N=2e6+114;
void build_border(string str,vector<int>& border){//数组从0开始计数
int str_len=str.length();
border[0]=0;
for(int i=1;i<str_len;i++){
int j=border[i-1];
while(j>0 && str[j]!=str[i])j=1+border[j-1]-1;//转到第二长的可匹配前缀
//-1是因为字符串从0开始,border[j-1]长度-1才是正确的位置 ,+1是因为要暴力扩展是否匹配
if(str[j]==str[i])j++;
border[i]=j;
}
return;
}
signed main(){
IOS
string s1,s2;
cin>>s1>>s2;
int len2=s2.length();
int len1=s1.length();
vector<int> border2(len2);
build_border(s2,border2);
int i=0,j=0;
while(i<len1){
if(s1[i]==s2[j]){
i++;
j++;
if(j-1==len2-1){
cout<<i-len2+1<<endl;
j=border2[j-1]-1+1;
}
}
else{
if(j>0){
j=border2[j-1]-1+1;//滑动后再次循环
}
else{
i++;
}
}
}
for(int i=0;i<len2;i++){
cout<<border2[i]<<" ";
}
return 0;
}