【字符串匹配】【BKDRhash||KMP】

题目描述
给定一个字符串 A 和一个字符串 B ,求 B 在 A 中的出现次数。A 和 B中的字符均为英语大写字母或小写字母。 A 中不同位置出现的 B 可重叠。

输入格式
输入共两行,分别是字符串 A 和字符串 B 。

输出格式
输出一个整数,表示 B 在 A 中的出现次数。

样例一
input

zyzyzyz
zyz
output

3
限制与约定
对于100%的数据:1≤A,B的长度≤106,A、B仅包含大小写字母。1≤A,B的长度≤106,A、B仅包含大小写字母。
时间限制:1s1s
空间限制:256MB256MB
T

这道题题意很简单,是字符串hs和KMP的裸题

字符串hs是一个准确率不是100%的算法,它的做法略玄学

就是把一个字符串按ASC码用一个进制(也叫seed,通常是131,13131)转成一个数字,并且使用unsigned long long自然溢出,

匹配时用小串的一部分和大串的一部分对比hs值实现匹配

代码如下

 1 #include<cstdio>
 2 #include<algorithm>
 3 #include<cstring>
 4 #define N 1000055
 5 #define seed 13131
 6 using namespace std;
 7 typedef unsigned long long ull;
 8 char a[N],b[N];
 9 int alen,blen;
10 long long cnt;
11 ull se[N],aa,abc[N];
12 inline void init()
13 {
14     scanf("%s%s",a+1,b+1);
15     se[0]=1;
16     alen=strlen(a+1),blen=strlen(b+1);
17     for(int i=1;i<=alen;i++)
18         se[i]=se[i-1]*seed,
19         abc[i]=abc[i-1]*seed+(a[i]-'0');
20     for(int i=1;i<=blen;i++)
21         aa=aa*seed+(b[i]-'0');
22 }
23 int main()
24 {
25     init();
26     for(int i=1;i+blen-1<=alen;i++)
27     {
28         int l=i,r=l+blen-1;
29         if(aa==abc[r]-abc[l-1]*se[r-l+1])cnt++;
30     }
31     printf("%lld
",cnt);
32     return 0;
33 }

然后是一种绝对准确,但是会比hs慢的算法,它叫KMP,名字取自三位大佬的名字的首字母

思想就是在失配时候不是调到头,而是利用之前的信息,跳到一个更佳的位置,从而节约时间复杂度

nxt数组的求法是算法的精髓

 1 void getnxt()
 2 {
 3     int k=0,j=1;
 4     nxt[1]=0;
 5     while(j<=plen)
 6     {
 7         if(k==0||p[j]==p[k])
 8             k++,j++,nxt[j]=k;
 9         else
10             k=nxt[k];
11     }
12 }

我习惯右移一位存储所以和网上的代码不太一样

网上很多讲解,不再赘述

那里的nxt[1]=0是最神奇的地方,用手模拟一下会发现当第一位失配时候,这么做就可以巧妙的解决

求的时候这么求

 1 int solvebyKMP()
 2 {
 3     int pt=1,pp=1,fin=0;
 4     while(pt<=tlen)
 5     {
 6         if(t[pt]==p[pp]||pp==0)
 7             pt++,pp++;
 8         else pp=nxt[pp];
 9         if(pp==plen+1)fin++,pp=nxt[pp];
10     }
11     return fin;
12 }

然后就能解决,

关于nxt数组的应用还有很多,以后的博客中会讲到

 1 #include<cstdio>
 2 #include<cstring>
 3 #define N 1000111
 4 #define clear(a,val) memset(a,val,sizeof(a))
 5 using namespace std;
 6 char t[N],p[N];
 7 int tlen,plen;
 8 int nxt[N];
 9 void getnxt()
10 {
11     int k=0,j=1;
12     nxt[1]=0;
13     while(j<=plen)
14     {
15         if(k==0||p[j]==p[k])
16             k++,j++,nxt[j]=k;
17         else
18             k=nxt[k];
19     }
20 }
21 int solvebyKMP()
22 {
23     int pt=1,pp=1,fin=0;
24     while(pt<=tlen)
25     {
26         if(t[pt]==p[pp]||pp==0)
27             pt++,pp++;
28         else pp=nxt[pp];
29         if(pp==plen+1)fin++,pp=nxt[pp];
30     }
31     return fin;
32 }
33 int main()
34 {
35     scanf("%s%s",t+1,p+1);
36     tlen=strlen(t+1),plen=strlen(p+1); 
37     getnxt();
38     printf("%d",solvebyKMP());    
39     return 0;
40 }
原文地址:https://www.cnblogs.com/Qin-Wei-Kai/p/10204339.html