kmp 基础详解
来源:互联网 发布:2020软件 编辑:程序博客网 时间:2024/06/05 11:47
断更许久。。。开学了对不对要拼命
刷(wan)题(you)了(xi)
不能浪费大好青春啊的!
我旁边这位小同学讲了一个星期的kmp终于才讲清楚了QAQ
(好像不能叫小同学他好像还比我大QAQ)
作为巩固决定写篇文章来温习一下
我尽我所能写好吧
之所以叫做KMP,是因为这个算法是由Knuth、Morris、Pratt三个提出来的,取了这三个人的名字的头一个字母。
讲那么多不就是处理字符串的一个东东嘛
比如说判断B串是否为A串的字串
为什么说他好呢
“因为快啊”
确实,KMP的最坏情况也只需要O(nm)
所以….废话讲完了
先贴代码
…..还有题目 poj3461 Oulipo
#include <cstdio>#include <cstring>using namespace std;int i,j,lena,lenb,n,ans,p[10010];char a[1000010],b[10010];int main(){ scanf("%d",&n); while (n--) { scanf("%s",b+1);lenb=strlen(b+1); scanf("%s",a+1);lena=strlen(a+1); p[1]=0;j=0; for (i=2;i<=lenb;i++) { while (j>0&&b[i]!=b[j+1]) j=p[j]; if (b[i]==b[j+1]) j++; p[i]=j; } j=0;ans=0; for (i=1;i<=lena;i++) { while (j>0&&a[i]!=b[j+1]) j=p[j]; if (a[i]==b[j+1]) j++; if (j==lenb) { ans++; } } printf("%d\n",ans); } return 0;}
我们用两个指针i和j分别表示,A[i-j+ 1..i]与B[1..j]完全相等。也就是说,i是不断增加的,随着i的增加j相应地变化,且j满足以A[i]结尾的长度为j的字符串正好匹配B串的前 j个字符(j当然越大越好),现在需要检验A[i+1]和B[j+1]的关系。当A[i+1]=B[j+1]时,i和j各加一;什么时候j=m了,我们就 说B是A的子串(B串已经整完了),并且可以根据这时的i值算出匹配的位置。当A[i+1]<>B[j+1],KMP的策略是调整j的位置 (减小j值)使得A[i-j+1..i]与B[1..j]保持匹配且新的B[j+1]恰好与A[i+1]匹配(从而使得i和j能继续增加)。
举个栗子
A=”abababaababacb”,B=”ababacb”,
i = 1 2 3 4 5 6 7 8 9 ……A = a b a b a b a a b a b …B = a b a b a c bj = 1 2 3 4 5 6 7此 时,A[6]<>B[6]。这表明,此时j不能等于5了,我们要把j改成比它小的值j'。j'可能是多少呢?仔细想一下,我们发现,j'必须 要使得B[1..j]中的头j'个字母和末j'个字母完全相等(这样j变成了j'后才能继续保持i和j的性质)。这个j'当然要越大越好。在这里,B [1..5]="ababa",头3个字母和末3个字母都是"aba"。而当新的j为3时,A[6]恰好和B[4]相等。于是,i变成了6,而j则变成了 4:i = 1 2 3 4 5 6 7 8 9 ……A = a b a b a b a a b a b …B = a b a b a c bj = 1 2 3 4 5 6 7从上面的这个例子,我们可以看到,新的j可以取多少与i无关,只与B串有关。我们完全可以预处理出这样一个数组P[j],表示当匹配到B数组的第j个字母而 第j+1个字母不能匹配了时,新的j最大是多少。P[j]应该是所有满足B[1..P[j]]=B[j-P[j]+1..j]的最大值。再后来,A[7]=B[5],i和j又各增加1。这时,又出现了A[i+1]<>B[j+1]的情况:i = 1 2 3 4 5 6 7 8 9 ……A = a b a b a b a a b a b …B = a b a b a c bj = 1 2 3 4 5 6 7由于P[5]=3,因此新的j=3:i = 1 2 3 4 5 6 7 8 9 ……A = a b a b a b a a b a b …B = a b a b a c bj = 1 2 3 4 5 6 7这时,新的j=3仍然不能满足A[i+1]=B[j+1],此时我们再次减小j值,将j再次更新为P[3]:i = 1 2 3 4 5 6 7 8 9 ……A = a b a b a b a a b a b …B = a b a b a c bj = 1 2 3 4 5 6 7现在,i还是7,j已经变成1了。而此时A[8]居然仍然不等于B[j+1]。这样,j必须减小到P[1],即0:i = 1 2 3 4 5 6 7 8 9 ……A = a b a b a b a a b a b …B = a b a b a c bj = 0 1 2 3 4 5 6 7终于,A[8]=B[1],i变为8,j为1。事实上,有可能j到了0仍然不能满足A[i+1]=B[j+1](比如A[8]="d"时)。因此,准确的说法是,当j=0了时,我们增加i值但忽略j直到出现A[i]=B[1]为止。
这就是以下这一段
for (i=1;i<=lena;i++) { while (j>0&&a[i]!=b[j+1]) j=p[j]; if (a[i]==b[j+1]) j++; if (j==lenb) { ans++; } }
那么我们怎么快速知道要跳到哪一格呢?
很简单吗
预处理一遍B
即复制一个B,存为B’
然后让B和B’来比较
不懂得可以再看一遍上面的解释。
p[1]=0;j=0; for (i=2;i<=lenb;i++) { while (j>0&&b[i]!=b[j+1]) j=p[j]; if (b[i]==b[j+1]) j++; p[i]=j; }
这里的p[i]=j是为了能让程序继续做下去,因为我们有可能找到多处匹配。所以为了避免卡掉… 0.0
所以….完了
本文章大部分来自Matrix67
所谓我的巩固就是在写的同时顺便看多一次
- kmp 基础详解
- KMP-基础
- KMP基础
- KMP基础
- KMP算法详解 【KMP】
- kmp 详解
- KMP详解~
- KMP详解
- KMP详解~
- KMP详解
- KMP详解
- KMP详解
- KMP详解
- KMP详解
- KMP详解
- KMP详解
- KMP详解
- kmp详解
- vs2012使用mscomm串口通讯方法及相关问题
- Android仿IOS 弹出框的实现
- [LeetCode]463. Island Perimeter
- 常用正则表达式
- Blockchain的鱼和熊掌系列(12)Zero-Knowledge Proof
- kmp 基础详解
- js控制div点击隐藏显示
- CF 782 B CoB. The Meeting Place Cannot Be Change 3分求极值
- ECMAScript 6网页样式修正器
- 关于手机端点击HTML input输入框页面放大的问题解决放法
- response.setHeader各种参数
- redis集群
- 为什么要使用ORM技术?和 JDBC 有何不一样?
- 浅谈WEB前后端分离