字符串匹配--(K)MP模板

大白书型模板,并没有写成函数形式:

这个是下标从0开始的:

此外,对于一个长度为 m 的串自匹配,在此模板中 m-p[m] 就是这个串的最小循环节长度(最后一个循环可以不完整)

另一个关于自匹配后的失配指针的性质:对于该串的所有可以作为循环节的长度是:m-p[m] , m-p[p[m]] , m-p[p[p[m]]]……直到 p[x] = 0。

 

 1 #include<stdio.h>
 2 #include<string.h>
 3 
 4 const int maxn=1e6+5;
 5 const int maxm=1e4+5;
 6 
 7 char s[maxn],t[maxm];    //s为待匹配串,t为模板串
 8 int p[maxm];    //自匹配数组
 9 
10 int main(){
11     while(scanf("%s%s",s,t)!=EOF){    //这个是字符串从下标0开始的
12         int i,j,ans=0;    //ans记录字符串出现次数
13         int n=strlen(s),m=strlen(t);    //在题目中遇到过,其实strlen很慢,所以如果不先存起来可能有TLE的风险
14         p[0]=p[1]=0;    //初始化自匹配数组
15         for(i=1;i<m;i++){    //自匹配
16             j=p[i];
17             while(j&&t[i]!=t[j])j=p[j];
18             p[i+1]=t[i]==t[j]?j+1:0;
19         }
20         j=0;            //注意 j=0
21         for(i=0;i<n;i++){    //串匹配
22             while(j&&s[i]!=t[j])j=p[j];
23             if(s[i]==t[j])j++;
24             if(j==m){
25                 ans++;        //此处记录出现次数(模板串在待匹配串中可重叠),或改为直接break表示是否出现过
26             }
27         }
28         printf("%d\n",ans);
29     }
30     return 0;
31 }

 

 

 

数组下标从1开始:

 1 #include<stdio.h>
 2 #include<string.h>
 3 
 4 const int maxn=1e6+5;
 5 const int maxm=1e4+5;
 6 
 7 char s[maxn],t[maxm];
 8 int p[maxm];
 9 
10 int main(){
11     while(scanf("%s%s",s+1,t+1)!=EOF){   // 。。这个是从下标1开始的,恩修改的还是比较多的所以不是很建议
12         int i,j,ans=0;
13         int n=strlen(s+1),m=strlen(t+1);
14         p[1]=p[2]=1;
15         for(i=2;i<=m;i++){
16             j=p[i];
17             while(j>1&&t[i]!=t[j])j=p[j];
18             p[i+1]=t[i]==t[j]?j+1:1;
19         }
20         j=1;
21         for(i=1;i<=n;i++){
22             while(j>1&&s[i]!=t[j])j=p[j];
23             if(s[i]==t[j])j++;
24             if(j==m+1){
25                 ans++;
26             }
27         }
28         printf("%d\n",ans);
29     }
30     return 0;
31 }

 

转载于:https://www.cnblogs.com/cenariusxz/p/4509794.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值