史上最好理解的KMP算法
来源:互联网 发布:金十数据官网 编辑:程序博客网 时间:2024/05/16 18:21
KMP算法的解释很多,但是大多都晦涩难懂。
我看了好几篇,决定把其中讲得比较好的几篇归纳一下。
但是版权属于它们:
The Knuth-Morris-Pratt Algorithm in my own words
字符串匹配的KMP算法
如果你看不懂KMP算法,那就看一看这篇文章
暴力匹配算法
首先,我假设你已经是一个已经懂暴力匹配算法的人了。
但是暴力匹配算法有一个问题:当你知道你的目标串和搜索串不匹配的时候,它已经附带了一些信息。
比如在如图匹配,实际上目标串已经匹配到了第七个字符D
如果接下来你还是把A往后移动一格,实际上你浪费了这次匹配。你应该把A往后移动四格才对。
而利用到了这个信息的就是KMP算法:
已知部分匹配表的KMP算法
首先我们先给出一个部分匹配表:
这个表你先用着,具体怎么生成接下来会说。
Step1:
已知空格和D不匹配但是前面六格是匹配的。查表可知,对后一个匹配字符B对应的部分匹配值为2,根据如下公式
移动位数=已匹配的字符数-对应的部分匹配值
因为6-2=4,所以搜索词移动4位。
再来试一次:
因为空格与c不匹配,搜索词还要继续往后移动。这时,已匹配的字符数为2(“AB”),对应的部分匹配值为0.所以,移动位数=2-0,结果为2,于是将搜索词后移两位。
依次类推。
而匹配串是怎么产生的呢?
部分匹配表的产生
首先来了解前缀和后缀的概念
“前缀”指除了最后一个字符以外,一个字符串的全部头部组合;”后缀”指除了第一个字符以外,一个字符串的全部尾部组合。
产生依据:
- “A”的前缀和后缀都为空集,共有元素的长度为0;
- “AB”的前缀为[A],后缀为[B],共有元素的长度为0;
- “ABC”的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;
- “ABCD”的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;
- “ABCDA”的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为”A”,长度为1;
- “ABCDAB”的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为”AB”,长度为2;
- “ABCDABD”的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0。
直观来看是两张图:
绿色是相同的字符串
java代码
但是看到求部分匹配表的java代码,我们又一次懵逼了。
public int[] getNext(String b){ int len=b.length(); int j=0; int next[]=new int[len+1];//next表示长度为i的字符串前缀和后缀的最长公共部分,从1开始 next[0]=next[1]=0; for(int i=1;i<len;i++)//i表示字符串的下标,从0开始 {//j在每次循环开始都表示next[i]的值,同时也表示需要比较的下一个位置 while(j>0&&b.charAt(i)!=b.charAt(j))j=next[j]; if(b.charAt(i)==b.charAt(j))j++; next[i+1]=j; } return next;}
为什么计算部分匹配表的时候不按套路出牌啊?为啥代码这么简单啊。
但是我们要知道,部分匹配表也是有信息可以利用的。
如图
当我们知道第j(此处为5)个字符的部分匹配值为i(此处为1)的时候,求第j+1(6)个字符的部分匹配值,我们只需要判断第i+1(2)个字符是不是和第j+1(6)是不是相等就可以了。如果相等,则第j+1(6)的部分匹配值必为i+1(2)。
所以代码有一行是:
if(b.charAt(i)==b.charAt(j))j++; next[i+1]=j;
但是如果这两个字符不相等呢?
从前面来找子前后缀
1 、如果要存在对称性,那么对称程度肯定比前面这个的对称程度小,所以要找个更小的对称,这个不用解释了吧,如果大那么就继承前面的对称性了。
2 、如果还是不相等,要找更小的对称,必然在对称内部还存在子对称,而且这个必须紧接着在子对称之后。
while(j>0&&b.charAt(i)!=b.charAt(j))j=next[j];
- 史上最好理解的KMP算法
- 史上最好的BP算法图解
- KMP算法的理解
- KMP算法的理解
- 【算法】KMP的理解
- KMP算法的理解
- KMP算法的理解
- KMP算法的理解
- KMP算法的理解
- [KMP]个人对于KMP算法的理解
- KMP算法的详细理解
- KMP算法的个人理解
- 对KMP算法的理解
- 对KMP算法的理解
- 对KMP算法的理解
- KMP算法的理解(二)
- 关于KMP算法的理解
- 对于KMP算法的理解
- bzoj3315
- 进程&线程间通信方式总结
- Hibernate的主配置文件hibernate.cfg.xml
- 1011. A+B和C (15)
- 定点数与浮点数区别
- 史上最好理解的KMP算法
- Python机器学习(01)
- [AtCoder2045]Salvage Robots 动态规划
- 1.3快速排序
- Linux环境下ELK环境搭建,以及碰到的问题
- VirtualBox(启动失败:intel_rapl no valid rapl domains found in package 0 error VirtualBox)
- poj 3414
- FPGA中浮点运算实现方法——定标
- tensorflow学习笔记八:TensorFlow官网教程Convolutional Neural Networks 难点详解