浅谈KMP算法及实现
来源:互联网 发布:华艺服装淘宝店 编辑:程序博客网 时间:2024/05/21 11:11
题目描述
这里通过lintcode上的字符串查找这道题,引入字符串匹配问题。
对于一个给定的 source 字符串和一个 target 字符串,你应该在 source 字符串中找出 target 字符串出现的第一个位置(从0开始)。如果不存在,则返回 -1。样例如果 source = "source" 和 target = "target",返回 -1。如果 source = "abcdabcdefg" 和 target = "bcd",返回 1。
BF匹配算法(蛮力匹配算法)
算法思想
从主串S的第 pos 开始,和模式串T的第一个字符进行比较,若相等,则继续逐个比较后续的字符;否则回溯到主串S的第 pos+1 字符位置处重新与模式串T进行比较。直到模式串T中的每一个字符依次与主串S的一个连续字符序列完全相同,则称匹配成功,此时返回模式字符串T的第一个字符在主串S中的位置;否则匹配失败,返回-1。
时间复杂度
n,m分别是主串和模式串的长度最坏情况下:O(n*m)
代码实现
class Solution { public int strStr(String source, String target) { if(source==null || target==null) return -1; //这里规定下标从1开始,当然也可以从0开始 int i=1,j=1; int slen=source.length(); int tlen=target.length(); if(tlen==0) return 0; if(slen==0 || slen<tlen) return -1; while(i<=slen && j<=tlen){ if(source.charAt(i-1)==target.charAt(j-1)){ i++; j++; }else{ //计算匹配失败后回溯到的主串S位置(pos+1) //下标从0开始为: i=i-j+1; i=i-j+2; j=1; } } //匹配成功,返回出现下标 //为满足题目输出要求,下标从0开始。 if(j>tlen) return i-tlen-1; else return -1; }}
KMP匹配算法
算法思想
与BF算法相比,KMP算法消除了主串S匹配失败时的指针回溯。KMP算法当匹配失败时,主串S中的i指针不需回溯,而是根据已经得到的部分匹配结果将模式串尽可能远的向右滑动,然后继续进行比较。
匹配过程
假设主串S为: acabaabaabcacaabc
模式串为:abaabcac
这里需要使用到一个next数组(后面会提到,现在只需理解匹配过程)
(1)第一次匹配i 1 2 a c a b a a b a a b c a c a a b c a b a a b c a c ^j 1 2当i=2时主串与j=2时模式串不匹配,查表next[2]=1;则需要将模式串中第一个字符与i=2位置的字符进行匹配,即模式串后移一位。(2)第二次匹配i 1 2 a c a b a a b a a b c a c a a b c a b a a b c a c ^j 1next[1]=0,此时需要将主串和模式串都向后移动一位(此时j=0,移动一位即是模式串第一个字符),即从i=3与模式串T1重新比较(3)第三次匹配 i 1 2 3 ... 8 a c a b a a b a a b c a c a a b c a b a a b c a c ^j 1 ... 6next[6]=3,则需要将模式串中第3个字符与i=8位置的字符进行匹配,即模式串后移3位。(4)第四次匹配i 1 2 3 ... 8 ... 14 a c a b a a b a a b c a c a a b c a b a a b c a c ^ j 1 2 3 ... 9
关于next数组
next[j]表明当模式串中第j个字符与主串中相应的字符不相等时,在模式串中需要重新和主串中该字符进行比较的字符位置。
计算next数组
当next函数中定义的集合不为空时,next[j]的值等于串"T[1]T[2]...T[j-1]"的真前缀子串和真后缀子串相等时的最大子串长度+1。那么什么是真前(后)缀子串呢:就是不包含自身的前(后)缀子串。如:aba真前缀子串: a ab真后缀子串: a ba当j=1时,串不存在,next[1]=0;当j=2时,规定next[2]=1;要求next[j+1],串为"T[1]T[2]...T[j]",要找该串的真前缀子串等于该串的真后缀子串,即只需比较 T[j] 和 T[k] 是否相等(k=next[j]):如相等,next[j+1]=next[j]+1;否则,继续比较 T[j] 和 T[k'] 是否相等(k'=next[k])? 如相等,next[j+1]=next[k]+1; 否则,继续比较 T[j] 和 T[ next[k'] ] 是否相等? ... 如果直到 next[k*]=0 都不相等,则 next[j+1]=1;
算法时间复杂度
n,m分别是主串和模式串的长度时间复杂度为:O(n+m)
代码实现
class Solution { //求next数组的过程 public static int[] getNext(String str){ int len=str.length(); int[] next=new int[len+1]; next[1]=0; int j=1,k=0; while(j<len){ //要计算next[j+1]:比较T[j]和T[next[j]] if(k==0 || str.charAt(j-1)==str.charAt(k-1)){ ++j; ++k; next[j]=k; } else k=next[k]; } return next; } public static int strStr(String source, String target) { if(source==null || target==null) return -1; int slen=source.length(); int tlen=target.length(); if(tlen==0) return 0; if(slen==0 || slen<tlen) return -1; int[] next=getNext(target); int i=1,j=1; while(i<=slen && j<=tlen){ if(j==0 || source.charAt(i-1)==target.charAt(j-1)){ i++; j++; } else j=next[j]; } if(j>tlen) return i-tlen-1; else return -1; }}
KMP代码的优化
举个栗子
试着考虑这个问题,如果主串为"aaabaaaab",模式串为"aaaab"?
模式串对应的next函数值如下:
这个效率有点低,所以我们引入 nextval 数组:
其计算方式如下:nextval[1]=0;如计算nextval[j],则比较 T[j] 与 T[k](k=next[j])?如相等: nextval[j]=nextval[k];否则: nextval[j]=next[j];
代码如下
class Solution { public static int[] getNext(String str){ int len=str.length(); int[] next=new int[len+1]; next[1]=0; int j=1,k=0; while(j<len){ if(k==0 || str.charAt(j-1)==str.charAt(k-1)){ ++j; ++k; next[j]=k; } else k=next[k]; } return next; } //这里根据得到的next数组来计算nextval数组 public static int[] getNextVal(String str){ int len=str.length(); int[] nextval=new int[len+1]; int j=2,k=0; nextval[1]=0; int[] next=getNext(str); while(j<=len){ k=next[j]; if(str.charAt(j-1)==str.charAt(k-1)) nextval[j]=nextval[k]; else nextval[j]=next[j]; j++; } return nextval; } public static int strStr(String source, String target) { if(source==null || target==null) return -1; int slen=source.length(); int tlen=target.length(); if(tlen==0) return 0; if(slen==0 || slen<tlen) return -1; int[] nextval=getNextVal(target); int i=1,j=1; while(i<=slen && j<=tlen){ if(j==0 || source.charAt(i-1)==target.charAt(j-1)){ i++; j++; } else j=nextval[j]; } if(j>tlen) return i-tlen-1; else return -1; }}
两种算法的比较
BF算法时间复杂度为O(n*m),但实际执行近似与O(n+m),因此仍被使用。KMP算法仅当模式串与主串之间存在许多部分匹配情况下,才会比BF算法快。
阅读全文
0 0
- 浅谈KMP算法及实现
- KMP算法及实现
- KMP算法及改进KMP算法实现
- KMP算法及Java实现
- kmp算法原理及实现
- KMP算法原理及实现
- KMP算法及java实现
- 浅谈字符串匹配算法—BF算法及KMP算法
- 浅谈字符串匹配算法—BF算法及KMP算法
- 【算法总结】KMP算法及java实现
- kmp算法浅谈
- 浅谈KMP算法
- 浅谈KMP算法
- 浅谈kmp算法
- 浅谈KMP算法
- 浅谈扩展KMP算法
- 浅谈KMP算法
- KMP串匹配算法原理及实现
- 设计模式(补充)
- Mac 下MySQL的安装与修改密码
- 1806: [Ioi2007]Miners 矿工配餐
- 为什么要重写hashcode()方法以及如何重写hashcode和equals方法
- hdu 4638 Group
- 浅谈KMP算法及实现
- NLP深度学习 —— CS224学习笔记4
- 【驱动】uboot环境变量分析
- ccf 201612-4 压缩编码
- 【SikuliX】SikuliX+Vysor实现安卓app自动化测试
- 常用开关电源拓扑演进
- Hadoop小案例
- 在参数封装对象Page中使用in查询多项数据记录
- JS中window对象的使用