字符串匹配之KMP算法(POJ 3461 Oulipo)
来源:互联网 发布:大唐玄怪来谒 知乎 编辑:程序博客网 时间:2024/05/14 15:23
几种常见的字符串匹配算法
常见的几种字符串匹配算法包括KMP算法,BM算法,Horspool算法,Sunday算法,fastsearch算法,KR算法等等。这里主要介绍一下KMP算法的匹配法则。
KMP算法思想:
KMP算法是由D.E.Knuth与V.R.Pratt和J.H.Morris同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。作为经典的前缀匹配算法,我们来探索一下它的神秘之处。
首先,简单粗暴的字符串匹配算法是这样的:
从左往右,text链(母链)的 i=4 和pat链(子链)的 j=4 匹配失败,遇到障碍了怎么办呢?
pat链整体右移了一步。
在 i=1 和 j=0 处匹配失败,又遇到麻烦了。。。
pat链它又往后移动一步。
这是在 i=4 和 j=2 处匹配失败。。。
你猜它会怎么做?聪明!它又往后移动一步。并把这种匹配模式贯彻到底,直到 i[6..10]时text和pat完全匹配,走了6步。
下面再来看一下KMP算法遇到麻烦是怎么解决的:
KMP遇上麻烦了。。。
KMP一步跳到这了。。。
快看,KMP又跳了!!
它向后走了一步。
快看,AC的色彩!!它匹配成功了!!同样的问题,它只用了4步。
你是怎么做到的呀?简单粗暴以无比崇拜的眼光看着KMP
KMP清了清嗓子,骄傲却谦卑:KMP算法的优点就是字符串匹配失败后的回溯时,利用它**next数组的记忆功能**,避免了再次匹配已经匹配过的字符,从而实现跳跃前进。
next数组是这样来的:
对于模式串 pat = ABABA ,执行这段程序
void get_next(){ int i = 0, j = -1; next[0] = -1; while(i < lenp) { if(j == -1 || pat[i] == pat[j]) { i++; j++; next[i] = j; } else j = next[j]; }}你会得到这样一个序列:
这就是next[]数组了。
怎么样?发现了什么没?看 i = 4时, pat[2..4] == pat[0.. 2 ]。
再换一组:
看 i = 13,pat[7..13] == pat[0..6]。
发现了吧,其实**next数组的取值完全取决于模式串**,与主串无关。并且**next[ j ]的值要取到恰到好处**,以上例来讲,
next[ 13 ] == 6,这样就使得pat[ 0..6 ](从0到next[ 13 ])这7个字符与pat[ 7..13 ](13往前数7个)这7个字符完全一样。这就是恰到好处。
知道了这些,再结合上面的程序演示一些例子,我们会发现,我们肉眼凡胎就可以写出next数组的取值来。
随便给你一个模式串abcabcabcd,能直接写出它的next数组来吗?
说完了next数组,再看看KMP函数体吧!
void KMP(){ int i = 0, j = 0; while(i < lent && j < lenp) { if(j == -1 || text[i] == pat[j]) { j++; i++; } else j = next[j]; /*这里用到了next数组*/ }}
通过对主串text 和模式串pat 逐字符的比较,最终得以匹配。
各算法见仁见智的地方就是遇到“麻烦”时的应对策略。
拿刚开始的例子从开始走到结束亲自尝试一下
(建议回到刚开始亲自试一下)
最后,学习KMP算法要知道三句话:next数组起到记忆的作用;next数组的取值仅仅取决于模式串;next[ j ]的值要取到恰到好处。多了解一些别的算法思想对KMP算法的学习也有很大的帮助。
/* POJ 3461 代码附上 */#include <stdio.h>#include <string.h>char text[1000002], pat[10002];int next[10002];int ans, lent, lenp;void get_next(){ int i, j; i = 0; j = -1; next[0] = -1; while (i < lenp) { if (j == -1 || pat[i] == pat[j]) ++i, ++j, next[i] = j; else j = next[j]; }}void KMP(){ int i = 0, j = 0; get_next(); while (i < lent) { if (j == -1 || text[i] == pat[j]) ++i, ++j; else j = next[j]; if (j >= lenp) { ans++; j=next[j]; //如果不能子链重合 这边要改成j=0; } }}int main(){ int t; scanf("%d", &t); while (t--) { ans = 0; scanf("%s", pat);//子链 scanf("%s", text);//母链 lent = strlen(text); lenp = strlen(pat); KMP(); printf("%d\n", ans); } return 0;}
- 字符串匹配之KMP算法(POJ 3461 Oulipo)
- poj 3461 Oulipo(KMP 字符串匹配算法)
- poj 3461 Oulipo 字符串匹配 KMP算法
- POJ 3461 Oulipo(KMP字符串匹配)
- poj 3461 Oulipo kmp字符串匹配
- KMP 字符串匹配 POJ 3461 Oulipo
- POJ 3461 Oulipo(KMP匹配)
- Poj 3461 Oulipo(KMP算法)
- POJ 3461 Oulipo (KMP算法)
- kmp算法(POJ 3461 Oulipo)
- PKU3461(Oulipo)字符串匹配-KMP算法
- HDU 1686 Oulipo(KMP算法 字符串匹配)
- poj 3461 Oulipo KMP算法
- poj 3461 Oulipo KMP算法
- poj 3461 Oulipo (求匹配字符串的个数)(KMP)
- POJ-3461 Oulipo-匹配的字符有几个(KMP算法)
- POJ 3461 Oulipo(KMP求匹配次数)
- Oulipo poj 3461 KMP连续匹配(有重合)
- 从你的Android手机屏幕获取你的隐私
- 关于中文乱码问题
- 2014 Multi-University Training Contest 2 1011 ZCC Loves Codefires 解题报告
- js 匿名函数和闭包
- 168 房间安排
- 字符串匹配之KMP算法(POJ 3461 Oulipo)
- js 当鼠标移到单元格(tr、td)背景变色 多种解决方案
- 169 素数
- Jquery的学习(一)入门和基础核心
- js return
- 171 聪明的kk
- 魔方机器人之下位机编程-----两种串口通信方式的比较
- 用javascript实现5秒页面跳转
- 【设计模式】建造者模式