对于已知的字符串t,想在s中找到一个他的満射,那么我们就要在s字符串中寻找与t字符串形式相同的字符串,那么怎么样的才是形式相同的字符串呢?因此引入一个特殊的hash规则,对于t串的字符i向后找第一个与他相同的字符串的位置,他们之间的距离(如果没有相同则为1)乘该位置的xp值,那么就能得到一个代表这个形式的数字。
再从s字符串中,从头到尾枚举,每个串,应该的形式,如果相等即可。
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <set>
#include <vector>
#include <map>
#define MOD 1000000007
#define ll long long
using namespace std;
const int M=1e6+10;
int lens,lent;
char s[M],t[100005];
const int base=23;
int hs_t;
vector<int>to[M];
int last[25],xp[100005];
void get_t()
{
memset(last,0,sizeof(last));
for(int i=lent-1;i>=0;i--)
{
int tmp=1;
if(last[t[i]-'a']>0)
{
tmp=last[t[i]-'a']-i+1;//求出t[i],i位置后面第一个i之间的距离
}
last[t[i]-'a']=i;
hs_t+=tmp*xp[lent-1-i];//位置信息
}
}
void get_to()
{
memset(last,0,sizeof(last));
for(int i=lens-1;i>=0;i--){
int nxt;
if(last[s[i]-'a']>0){
nxt=last[s[i]-'a'];
if(nxt-i<lent) to[nxt].push_back(i);//从nxt位置往前找第一个跟nxt字符相同的位置,在lent范围内
}
last[s[i]-'a']=i;
}
}
void init(){
xp[0]=1;
for(int i=1;i<100005;i++)
xp[i]=xp[i-1]*base;
}
int dis[M];
int main()
{
scanf("%s",s);
scanf("%s",t);
lent=strlen(t);
lens=strlen(s);
if(lens<lent)return 0;
init();
get_t();
get_to();
int hs=0;
for(int i=0;i<lens;i++)
{
dis[i]=1;
hs=hs*base+1;
if(i>=lent)hs-=dis[i-lent]*xp[lent];
for(int j=0;j<to[i].size();j++)
{
int f=to[i][j];
hs+=(i-f+1-dis[f])*xp[i-f];
dis[f]=i-f+1;
}
if(i>=lent-1&&hs_t==hs)
cout<<i-lent+2<<endl;
}
return 0;
}