字符串 Hash
字符串 Hash:( ext{Hash}(a)=sum{a_i x^i} mod{p})。本质是一种进制的思想。
双 Hash:保证正确性。
#define mod1 1000000007
#define mod2 1000000009
ll n,p1[251],p2[251],p1b[251],p2b[251],s1[251],s2[251];
char c[251];
ll qpow(ll x,ll y,ll mod) {
ll res=1;
while(y) {
if(y&1) res=res*x%mod;
x=x*x%mod; y>>=1;
}
return res;
}
int main() {
scanf("%lld",&n); scanf("%s",c+1);
int l1,r1,l2,r2; scanf("%d%d%d%d",&l1,&r1,&l2,&r2);
if((r1-l1)!=(r2-l2)) {printf("No"); return 0; }
p1[0]=p2[0]=p1b[0]=p2b[0]=1;
for (int i=1;i<=n;i++) {
p1[i]=p1[i-1]*347%mod1;
p2[i]=p2[i-1]*347%mod2;
if(i==1) {
p1b[i]=qpow(347,mod1-2,mod1);
p2b[i]=qpow(347,mod2-2,mod2);
} else {
p1b[i]=p1b[i-1]*p1b[1]%mod1;
p2b[i]=p2b[i-1]*p2b[1]%mod2;
}
s1[i]=(s1[i-1]+c[i]*p1[i])%mod1;
s2[i]=(s2[i-1]+c[i]*p2[i])%mod2;
}
ll hash1,hash2,hash3,hash4;
hash1=(s1[r1]-s1[l1-1]+mod1)%mod1*p1b[l1-1]%mod1;
hash2=(s2[r1]-s2[l1-1]+mod2)%mod2*p2b[l1-1]%mod2;
hash3=(s1[r2]-s1[l2-1]+mod1)%mod1*p1b[l2-1]%mod1;
hash4=(s2[r2]-s2[l2-1]+mod2)%mod2*p2b[l2-1]%mod2;
if(hash1==hash3&&hash2==hash4) printf("Yes %lld %lld %lld %lld",hash1,hash3,hash2,hash4)
else printf("No %lld %lld %lld %lld",hash1,hash3,hash2,hash4);
return 0;
}
Knuth–Morris–Pratt (KMP)
字符串匹配问题:给出文本串和模式串,求出模式串在文本串中所有出现的位置。
利用已经部分匹配这个有效信息,保持i指针不回溯,通过修改j指针,让模式串尽量地移动到有效的位置。
当 (P_k=P_j) 时,有 ( ext{next}(j+1)= ext{next}(j) + 1);
当 (P_k e P_j) 时,有 (k= ext{next}(k))。
char s[N], p[M];
int sl, pl;
int nex[M];
inline void getnex() { // 求前缀数组
int k=-1, j=0; nex[0]=-1;
while (j<pl) {
if (k==-1 || p[j]==p[k]) { // 当两个字符相等时要跳过
if (p[++j]==p[++k]) nex[j]=nex[k]; else nex[j]=k;
} else k=nex[k];
}
}
inline void kmp() {
int i=0, j=0; // i主串的位置,j模式串的位置
while (i<sl && j<pl) {
if (j==-1 || s[i]==p[j]) i++, j++; else j=nex[j]; // 当j为-1时,要移动的是i,当然j也要归0
if (j==pl) printf("%d
", i-pl+1), j=nex[j];
}
}
int main() {
scanf("%s", s); scanf("%s", p);
sl=strlen(s); pl=strlen(p);
getnex();
kmp();
return 0;
}
字典树 Trie
按前缀分类。
具体形态为一棵有根树,每条边上记录一个字符,从根到一个节点路径上所有字符接起来即这个节点所代表的字符串。实现时,我们对每个节点维护与字符集一一对应的儿子集合。插入字符串时,依次遍历串中每个字符,并从根开始走每个字符对应的儿子,如果不存在则新建对应节点。时间复杂度为 字符串总长,空间复杂度为 字符串总长 ( imes) 字符集。
空间优化:用 map 来存储儿子优化空间,代价是时间复杂度多一个 log。