自己关于KMP算法的理解
2014-11-10 08:07
281 查看
数据结构学到KMP,刚看到时也是弄了好长时间没有看懂,琢磨四天后问了一位大神,终于有点眉目了,理解之后自己又写出求next数组的方法,然后拉了一道题出来练练,过了,觉得好不容易弄懂,怕以后又忘掉,同时也检验一下自己是否真的理解,还是写下点东西记录一下吧。
感谢那位大神的同时还是感谢网上很多博客的,有一篇给我的帮助还是很大的,浅显易懂,如果有不明白的可以去看一下试试http://blog.csdn.net/yearn520/article/details/6729426
我就不像网上的博客引出传统暴力匹配的方法再介绍KMP,就直接从next数组开始吧。
next数组功能,举个例子
(默认下标从1开始)
我们将模式串进行匹配,如果第一位 a 就不符合,这个需要特殊处理就直接将整个字符串向后移一位就好;
(至于为什么是0,我不懂,因为下标已经是从1开始,有待考究)
如果第二位不符,说明第一位已经符合,我们看b的next值,为1,就将第一位的 a 向后移至第二位,再进行比较。(说不定原串中就从第二位开始就与模式串匹配上了)
第三位不符的话,next值还是1,我们就再将这个串的第1位移到不符的位置;(其实这个串,第一位和第三位都是a,把第一位移过来明显还是不符,所以算是一种浪费,可能在下面的nextval中会优化)
第四位不符,说明前三位符合,然而第三位与第一位相等,又是a,那就直接将第二位移到原来第四位的位置进行匹配。
第五位不符,同上;
第六位不符,说明 第四第五位 a b 都匹配上了,next 值为 3,那就把第三位移到原来的第六位;
第七位不符,同第三位;
第八位不符,同第四位;
上面写的功能中隐约也说明了next数组的来历,我们来看看它是怎么求的
第1位是0
第j位,j != 1,就是从第 1 位到第 j-1 位比较字串,前缀和后缀相等的最大长度再加 1 ,这里的长度不能大于j-2,也就是前缀和后缀要为前 j-1 位的真字串
比如
a b a b
虽然前三位是对称的,第四位的next值是 2 而不是 4 ,如果比到第四位出错,我们只能将第二位移过去。
其它情况,匹配不上只能将串的头再移到不匹配的地方了。
人工求倒是很好求,写入程序呢,一直调用substr来判断相等效率会很低,自然有更好的方法
这里就用到了我给的那位大神的博客中的讲解。再次致敬
然后呢,我主要说一下我对子对称的理解
就拿那个大神的例子
(a g c t a g c )( a g c t a g c) tg
对于next的理解不同,他求的next逐位+1右移便是我们讲的next
常规来看,第15位next 是8 ,第16 位按照累加的求法应该是1 吧,但是为什么是 5 呢?
我们知道原理来说,g之前 agct 与开头的 agct 相等构成对称,确实是5
然而,我们算到 g 的时候,我们知道应该有一串长度为n 的字串构成对称条件,就算没有,n = 0 ,g 的next 值也总是 n+1
对于前面的 t ,next 值为 8,意味着之前有7位构成对称,也就是前7位与之后7位相同;
而我们要求的 长度为n的字串除了最后一位 t 之外,之前的 n-1 位也是上面那 7 位的后 n-1 位,既然前7位与之后7位相同,这n-1位也是前7位的后 n-1 位;
所以,我们让 i = next [ i ],访问到 t 的next值,缩短比较的距离。另外判断 模式串 的next[i]位和第 i 位是否相等,(第一次肯定是不等的),不等的话就在进行
i = next [ i ],为什么呢,相当于递归了。
每次i = next [ i ]的操作都能保证那 n – 1位相等(方便叙述我直接用 n-1 实际上 n的值到最后匹配上时才可以确定 ),我们只是一直在判断 t 是否能被匹配上,当匹配上时,第16位的next 就是匹配上的 t 的位置。
所以我们可以确定这种按照自己理解写出的算法:
that is it
有空我还会总结nextval
感谢那位大神的同时还是感谢网上很多博客的,有一篇给我的帮助还是很大的,浅显易懂,如果有不明白的可以去看一下试试http://blog.csdn.net/yearn520/article/details/6729426
我就不像网上的博客引出传统暴力匹配的方法再介绍KMP,就直接从next数组开始吧。
next数组功能,举个例子
模式串 | a | b | a | a | b | c | a | c |
next值 | 0 | 1 | 1 | 2 | 2 | 3 | 1 | 2 |
我们将模式串进行匹配,如果第一位 a 就不符合,这个需要特殊处理就直接将整个字符串向后移一位就好;
(至于为什么是0,我不懂,因为下标已经是从1开始,有待考究)
如果第二位不符,说明第一位已经符合,我们看b的next值,为1,就将第一位的 a 向后移至第二位,再进行比较。(说不定原串中就从第二位开始就与模式串匹配上了)
第三位不符的话,next值还是1,我们就再将这个串的第1位移到不符的位置;(其实这个串,第一位和第三位都是a,把第一位移过来明显还是不符,所以算是一种浪费,可能在下面的nextval中会优化)
第四位不符,说明前三位符合,然而第三位与第一位相等,又是a,那就直接将第二位移到原来第四位的位置进行匹配。
第五位不符,同上;
第六位不符,说明 第四第五位 a b 都匹配上了,next 值为 3,那就把第三位移到原来的第六位;
第七位不符,同第三位;
第八位不符,同第四位;
上面写的功能中隐约也说明了next数组的来历,我们来看看它是怎么求的
第1位是0
第j位,j != 1,就是从第 1 位到第 j-1 位比较字串,前缀和后缀相等的最大长度再加 1 ,这里的长度不能大于j-2,也就是前缀和后缀要为前 j-1 位的真字串
比如
a b a b
虽然前三位是对称的,第四位的next值是 2 而不是 4 ,如果比到第四位出错,我们只能将第二位移过去。
其它情况,匹配不上只能将串的头再移到不匹配的地方了。
人工求倒是很好求,写入程序呢,一直调用substr来判断相等效率会很低,自然有更好的方法
这里就用到了我给的那位大神的博客中的讲解。再次致敬
然后呢,我主要说一下我对子对称的理解
就拿那个大神的例子
(a g c t a g c )( a g c t a g c) tg
对于next的理解不同,他求的next逐位+1右移便是我们讲的next
常规来看,第15位next 是8 ,第16 位按照累加的求法应该是1 吧,但是为什么是 5 呢?
我们知道原理来说,g之前 agct 与开头的 agct 相等构成对称,确实是5
然而,我们算到 g 的时候,我们知道应该有一串长度为n 的字串构成对称条件,就算没有,n = 0 ,g 的next 值也总是 n+1
对于前面的 t ,next 值为 8,意味着之前有7位构成对称,也就是前7位与之后7位相同;
而我们要求的 长度为n的字串除了最后一位 t 之外,之前的 n-1 位也是上面那 7 位的后 n-1 位,既然前7位与之后7位相同,这n-1位也是前7位的后 n-1 位;
所以,我们让 i = next [ i ],访问到 t 的next值,缩短比较的距离。另外判断 模式串 的next[i]位和第 i 位是否相等,(第一次肯定是不等的),不等的话就在进行
i = next [ i ],为什么呢,相当于递归了。
每次i = next [ i ]的操作都能保证那 n – 1位相等(方便叙述我直接用 n-1 实际上 n的值到最后匹配上时才可以确定 ),我们只是一直在判断 t 是否能被匹配上,当匹配上时,第16位的next 就是匹配上的 t 的位置。
所以我们可以确定这种按照自己理解写出的算法:
void getnext( string s , int next[] ) { s = '#' + s; //为了使下标从1开始 int len = s.size(); next[1] = 0; next[2] = 1; int i = 3 ; int j = 1 ; while ( i < len ) { if ( s[i - 1] == s[j] ) { next[i] = j + 1; i ++ ; j ++ ; } else { j = next [j] ; if ( j == 0) { j ++ ; next[i] = j ; i ++ ; } } } }那么匹配的过程也就是
int kmp(string s1,string s2,int next[]) { s1 = '#' + s1; // s1 对应 next 数组 s2 = '#' + s2; int len1 = s1.size(); int len2 = s2.size(); int i = 1 ; int j = 1 ; while( j < len2 ) { if ( s1[i] == s2[j] ) { i ++ ; j ++ ; } else { if(next[i] != 0 ) i = next[i]; else i = 1; //i = next[i]; } if ( i == len1) { return j - len1 + 1; break; } } }
that is it
有空我还会总结nextval
相关文章推荐
- 2018.1.25 关于KMP算法的一些自己的理解。
- 关于 ++i*--i 问题自己的理解
- 关于c/c++中的类型重定义错误的自己的理解
- oracle - 关于回滚段的一些特点及自己的理解
- 关于volley的一点自己的理解
- 关于多态的一些自己理解
- 关于KMP算法的一点个人理解
- 关于spring mvc的一点自己的理解
- 关于KMP算法的个人理解
- 关于在适配器中更新ui的方法(写这个东西只是为了自己理解,不要看,大家看不懂)
- IOS中自己关于Ivar和objc_property_t的理解,整理下网上资料
- 自己关于指针在函数中使用的理解和总结
- 关于委托自己的一点理解
- 自己关于Android中Matrix的理解
- 听了GDC2014关于关卡设计的讲座的总结与自己的理解
- 关于java方法多线程访问自己的理解
- 关于连接池自己的一理解
- 关于Andiroid SDcard 自己的一些理解
- 关于js闭包自己的理解
- 深度译文:机器学习那些事 关于自己的理解