KMP两种写法以及AC自动机失配数组间的区别
2017-08-20 13:25
197 查看
第一种 KMP
这一种是没有优化过的KMP,当第i位失配(模式串与文本串相应字符不同),需要使用的是next[i -1],该数组所存数据的意义是,与第i位字符有最长相同前缀(且不包括本身)的字符的位置。假设next[i-1] = j(j < i),那么第j位的前缀是完全属于第i位的前缀(不包括第i位和第j位)。因此当i失配时,就会跳到j去匹配,因为j的前缀与i在相同长度部分是完全相同的,所以可以保证j之前的所有位是匹配上的,只需要将第j位与相应的文本串进行比较即可。但是如果第i位与第j位字符相同,就会导致第j位同样无法匹配,这样的多余操作,因此有了第二种KMP,用新的next(失配指针数组)优化了这个问题。
第二种KMP
这种KMP是在第一种KMP的基础上的一个优化,当失配时能够更快的找到合适的位置进行匹配。在这种方法当中next数组(失配指针数组)相较于第一种解决了重复判断相同无效字符的问题。例如,当第i位失配时会令 i= next[i],所以next数组的意义为,与第i位有最长相同前缀,且第next[i]与第i位的字符不同。当第i位失配时,不会再像第一种进行可能无用的判断,能够有效的提高算法速度。在next数组的计算过程中,假设j<i那么我们已经得到了next[j],当我们遍历到第i位时,发现j位的前缀完全属于i的前缀(不包括j和i),那么j与i有最长相同前缀,如果j位字符与i位字符不同,那么next[i]
= j,如果相同的话,那么i失配时,如果跳到j肯定也会同样失配,所以直接跳到next[j],能够有效减少冗余操作,那么nex[i] = next[j].
AC自动机
AC自动机的关键就在于当建完字典树之后,计算fail指针。这与KMP中的next数组有异曲同工之妙,但是他们的意义相似却不完全相同。AC自动机中某一点的指针指向的是,在字典树中与它有最长相同前缀的节点(包括这两个节点储存的字符也相同)。这与第一种KMP是有区别的,第一种KMP存的是与第i位有最长相同前缀的位置,但是该位置与第i位字符是否相同我们并不需要知道,但是AC自动机要保证两个节点本身的字符也要相同,才能将失配指针指向。
这一种是没有优化过的KMP,当第i位失配(模式串与文本串相应字符不同),需要使用的是next[i -1],该数组所存数据的意义是,与第i位字符有最长相同前缀(且不包括本身)的字符的位置。假设next[i-1] = j(j < i),那么第j位的前缀是完全属于第i位的前缀(不包括第i位和第j位)。因此当i失配时,就会跳到j去匹配,因为j的前缀与i在相同长度部分是完全相同的,所以可以保证j之前的所有位是匹配上的,只需要将第j位与相应的文本串进行比较即可。但是如果第i位与第j位字符相同,就会导致第j位同样无法匹配,这样的多余操作,因此有了第二种KMP,用新的next(失配指针数组)优化了这个问题。
第二种KMP
这种KMP是在第一种KMP的基础上的一个优化,当失配时能够更快的找到合适的位置进行匹配。在这种方法当中next数组(失配指针数组)相较于第一种解决了重复判断相同无效字符的问题。例如,当第i位失配时会令 i= next[i],所以next数组的意义为,与第i位有最长相同前缀,且第next[i]与第i位的字符不同。当第i位失配时,不会再像第一种进行可能无用的判断,能够有效的提高算法速度。在next数组的计算过程中,假设j<i那么我们已经得到了next[j],当我们遍历到第i位时,发现j位的前缀完全属于i的前缀(不包括j和i),那么j与i有最长相同前缀,如果j位字符与i位字符不同,那么next[i]
= j,如果相同的话,那么i失配时,如果跳到j肯定也会同样失配,所以直接跳到next[j],能够有效减少冗余操作,那么nex[i] = next[j].
AC自动机
AC自动机的关键就在于当建完字典树之后,计算fail指针。这与KMP中的next数组有异曲同工之妙,但是他们的意义相似却不完全相同。AC自动机中某一点的指针指向的是,在字典树中与它有最长相同前缀的节点(包括这两个节点储存的字符也相同)。这与第一种KMP是有区别的,第一种KMP存的是与第i位有最长相同前缀的位置,但是该位置与第i位字符是否相同我们并不需要知道,但是AC自动机要保证两个节点本身的字符也要相同,才能将失配指针指向。
相关文章推荐
- 1.如何避免野指针2.获取字符串的两种方法。以及malloc,calloc,ralloc的使用注意点3.二维三维数组4.数组和函数的区别
- js---原生JS数组arr遍历方法forEach()和map()遍历的区别以及兼容写法
- poj 2752 KMPnext[]数组的理解 以及 两种优化
- json 的 使用方法以及与数组的区别
- 浅谈BroadCastReceiver两种注册方式以及其区别
- Java中有两种实现多线程的方式以及两种方式之间的区别
- java中创建String类型对象的两种方式以及在使用equals()和“==”两种方法时的区别
- Oracle集合(联合数组(索引表),嵌套表,变长数组,记录类型的嵌套表)的初始化与赋值,以及它们的区别
- C语言字符数组的两种形式与区别
- PHP中数组合并的两种方法及区别介绍 array_merge +
- PHP中数组合并的两种方法及区别介绍
- Java中有两种实现多线程的方式以及两种方式之间的区别
- typeof和instanceof的区别以及如何判断一个数组
- Java中有两种实现多线程的方式以及两种方式之间的区别
- JavaScript中的数组遍历forEach()与map()方法以及兼容写法介绍
- PHP中数组合并的两种方法及区别介绍
- 指针与数组的区别,以及函数的实现过程
- 原生JS forEach()和map()遍历的区别以及兼容写法
- 常见浏览器的宽高代码写法!有原生JavaScript和jquery两种写法-------------------------------以及我的个人网站
- Android 两种隐藏系统状态栏的写法的区别