- 浏览: 887370 次
- 性别:
- 来自: 武汉
文章分类
最新评论
-
小宇宙_WZY:
膜拜一下大神,解决了我一个大问题,非常感谢 orz
【解惑】深入jar包:从jar包中读取资源文件 -
JKL852qaz:
感谢,遇到相同的问题!
【解惑】深入jar包:从jar包中读取资源文件 -
lgh1992314:
为什么java中调用final方法是用invokevirtua ...
【解惑】Java动态绑定机制的内幕 -
鲁曼1991:
说的都有道理,protected只能被同一级包的类所调用
【解惑】真正理解了protected的作用范围 -
鲁曼1991:
...
【总结】String in Java
模式匹配: 在字符串S中,子串P的定位操作通常称做串的模式匹配。说白了,就是在一个字符串中寻找子串。在Suffix Trie和PAT tree中我们已经讨论过匹配子串的方法了。这里我们讨论一种线性匹配算法来寻找子串。
例: 我们要在S="ababcabcacbab"中查找子串P="abcac"。下图左侧是一种很普通的模式匹配算法
这种普通的模式匹配算法很简单,但时间复杂度是O(n*m)。其中n=S.length,m=T.length. 代价很高。难道真的要像第三趟到第四趟那样:好不容易匹配到S中的第7个位置,但由于不相同,则有回溯到第4个位置重新开始。
其实,每一次匹配过后,主串S中被匹配过的位置其实不用再匹配了。也就是上一趟匹配结果对下一趟有指导作用。 我们用一个证明来说明这一点(假如主串S=s1 s2 .... sn ,模式串P=p1 p2 ... pm )。
证明:当一趟匹配完成之后,我们发现si !=pj 。那么至少说明了模式串p1... p(j-1)是匹配成功的。也就是得到了: p1 p2 ... p(j-1) = s(i-j+1) s(i-j+2) ..... s(i-1) 。 比如第三趟 s7!=p5 => s2...s6=p1...p4 = "abca".
如果像上图左侧算法那样,从第三趟i=7回溯到第四趟i=4是有必要的话,那么也说第四趟可能完全匹配到了模式串P。好,我们现在就假设si != sj之后,i 回溯主串(i-j+1)的下一个位置上可以匹配成功模式串P,那么我们可以得到 p1 p2 ... p(j-1) =s(i-j+2) s(i-j+3) ... s(i)。
合并下标蓝色的两个式子,我们可以得到:
s(i-j+1) s(i-j+2) ..... s(i-1)= s(i-j+2) s(i-j+3) ... s(i)
也就是: s(i-j+1)= s(i-j+2)= s(i-j+3)= .... =s(i-1)=s(i)
我靠,主串S中全部的字符都一样,这种情况下才必须每一次都回到主串的下一个位置上重新开始。而只要有字符不同,就完全没有这个必要了。好了,基于这个证明成果,我们开始介绍KMP算法。
KMP 模式匹配 —— D.E.Knuth V.R.Pratt和J.H.Morris同时发现的。因此人们称它为克努特-莫里斯-莫拉特操作(简称KMP算法)。KMP的优势在于当每一趟匹配结果中出现了不等情况时,主串并不需要回溯位置i (上面已经证明),而只要 回溯模式串P即可 。也就是说,只需要在主串S的位置i 处重新与模式串的位置k进行比较(如上图右侧过程)。 那么这个 重新 需要定位的模式串k位置有什么要求呢,或者说我们怎么确定这个k呢。我们再用一个小小的证明来揭示( 还是假如主串S=s1 s2 .... sn ,模式串P=p1 p2 ... pm ):
证明:当一趟匹配完成之后,我们发现si !=pj 。此时首先可以肯定的是k< j,因为模式串j 必须回溯。
如果 s1 与 pk 有重新比较的必要,那么模式串P前k-1个字符必须满足下列关系式:
p1 p2 ... p(k-1)=s(i-k+1) s(i-k+2) ... s(i-1)
此外,由于经过额一趟的匹配之后,已经可以得到“部分匹配”结果,主串S中i 位置的前k个字符一定等于模式串P中j 位置上的前k个字符:
p(j-k+1) p(j-k+2) ... p(j-1) = s(i-k+1) s(i-k+2) ..... s(i-1) 。
合并两个蓝色的式子:
p1 p2 ... p(k-1) = p(j-k+1) p(j-k+2) ... p(j-1)
我们发现了,位置k的值取决于模式串P自己必须满足上面这个红色的式子。
失效函数: 当在模式串P的第j 个位置上发生匹配不成功时,需要将模式串回溯到位置 k处的这样一个f(j)=k 的函数,就叫做失效函数。其中j 和k 的值必须满足p1 p2 ... p(k-1) = p(j-k+1) p(j-k+2) ... p(j-1)。 也就是说 pj 的前k-1个字符必须等于pk 的前k-1 个字符。因此,失效函数f(j)的定义如下:
0 当j=1时
f(j) = Max{k|1<k<j 且 p1...p(k-1)=p(j-k+1)...p(j-1) }
1 不满足上面的情况
比如模式串P=“abcac”的每一个位置的失效函数如下:
j 1 2 3 4 5
P a b c a c
k=f(j) 0 1 1 1 2
失效函数的算法
假如f(j)=k,则表明 p1...p(k-1) = p(j-k+1)...p(j-1)。这说明 pj 的前k-1个字符必须等于pk 的前k-1 个字符。也就是说p1...pk一定是p1...pj的一个后缀子串。因此我们可以把模式串P与自身做KMP算法的匹配来求解这个K值。算法如下:
(1) 若 pk=pj, 则p1...p(k-1)pk= p(j-k+1)...p(j-1) pj 。 表明f(j+1)=k+1
(2) 若 pk!=pj , 则可以把求f(j+1)看成以P为主串和匹配串的模式匹配问题。即 pk!=pj 则比较pj与p(f(k)),如果pj==p(f(k)),则f(j+1)=f(k)+1。否则继续比较下去直到f(k)=0为止。
失效函数算法的运行时间是o(m).
KMP算法Java源代码
package net.hr.algorithm.string; public class KMP { private int[] next=null; private char[] mainAry=null; private char[] patternAry=null; public KMP(String main,String pattern){ this.mainAry=new char[main.length()+1]; this.patternAry=new char[pattern.length()+1]; System.arraycopy(main.toCharArray(),0,mainAry,1,main.length()); System.arraycopy(pattern.toCharArray(),0,patternAry,1,pattern.length()); this.next=new int[pattern.length()+1]; } /** * KMP匹配 * @param pos 从主串起始位置开始 */ public int match(int pos){ if(pos>mainAry.length) throw new IndexOutOfBoundsException(); failFunction(); int i=pos,j=1; while(i<mainAry.length&&j<patternAry.length){ if(j==0||mainAry[i]==patternAry[j]){ ++i; ++j; }else{ j=next[j]; } } if(j>=patternAry.length) return i-patternAry.length+1; else return 0; } /** * 匹配串失效函数 */ private void failFunction(){ int i=1,j=0; next[1]=0; while(i<patternAry.length-1){ if(j==0||patternAry[i]==patternAry[j]){ next[++i]=++j; }else{ j=next[j]; } } } /** * 测试 * @param args */ public static void main(String[] args) { KMP kmp=new KMP("acabaabaabcacaabc","abaabcac"); System.out.println(kmp.match(1)); } }
KMP算法效率
对于长度为n的文本串和长度为m的模式串进行模式匹配的运行时间为O(n+m) . 很显然,因为文本串在KMP算法中并不需要回溯,因此与模式串的比较次数为O(n)。但模式串要建立失效函数,所付出的代价是O(m)。因此总体的时间复杂度是O(m+n)。实际中,m要远小于n,因此近似可以认为KMP效率为O(n)。
但是KMP算法有种最坏的情况,当模式串P="aaaaa"时,即每一个字符都一样的时候。则失效函数为:
j 1 2 3 4 5
P a a a a a
f(j) 0 1 2 3 4
此时如果主串中的s[i]!=p[j]的时候,根据模式串P回溯j=f(j)的原则。s[i]需要从模式串P的最后一个字符一步一步回溯到第一个字符,每次都要比较一遍。这时的时间复杂度为O(m)。那么对于n个字符的S串而言,最差的时间复杂度就是O(n*m)了,退化成了蛮力匹配。
KMP和后缀树都可以用来匹配子串。因此我们这里与后缀树做一个比较,虽然后缀树在查找的过程中只需要大概O(m)的时间复杂度。对长度n的文本串建立后缀树最好的算法需要O(n)时间复杂度,因此后缀树大致也需要O(n+m) 。
发表评论
-
★经典问题—链表中的环问题
2010-06-29 14:43 4394转载:http://www.cppblog.com ... -
★经典问题—元素选择问题
2010-05-24 10:53 3298元素选择问题 : 给定线性序集中n个元素和一个整数k( ... -
【串和序列处理 8】最长平台问题
2010-04-28 16:41 36281、经典最长平台算法 已知一个已经从小到大 ... -
【排序结构7】 基数排序
2010-04-20 16:17 4503《桶排序 》中我们能够看到,数据值的范围越大,可能需要桶的个 ... -
【排序结构6】 桶排序
2010-04-19 20:28 22839从《基于比较的排序结构总结 》中我们知道:全依赖“比较”操作的 ... -
【排序结构5】 基于比较的内部排序总结
2010-04-18 16:15 6684★ 基于“比较”操作的内部排序性能大PK ... -
【排序结构4】 归并排序
2010-04-17 16:29 3258归并排序 O(N*logN) 是另一种效率很高的排序方法。&q ... -
【排序结构3】 选择排序
2010-04-14 21:10 3561(1) 简单选择排序 O(N^2) 一趟简单选择排序 ... -
【排序结构2】交换排序
2010-04-14 11:04 25471、起泡排序 O(N^2) ... -
【排序结构1】插入排序
2010-04-13 17:11 29731、基本概念介绍 (1) 如果待排序列中有两个 ... -
【串和序列处理 7】LIS 最长递增子序列
2010-03-25 16:37 5771LIS: 给定一个字符串序列S={x0,x1,x2,.. ... -
【串和序列处理 6】LCS 最长公共子序列
2010-03-23 17:38 8761LCS:又称 最长公共子序列。 其中子序列(subse ... -
★经典问题—欧几里得求最大公约数
2010-03-20 19:21 3322问题:快速求取正整数a,b的最大公约数? ... -
【串和序列处理 4】Suffix Trie 子串匹配结构
2010-03-20 15:15 9031Suffix Trie : 又称后 ... -
【串和序列处理 3】Trie Tree 串集合查找
2010-03-18 13:40 17552Trie 树, 又称字典树,单词查找树。它来源于retr ... -
【串和序列处理 2】字符串编辑距离算法
2010-03-15 08:45 11059我们来看一个实际应用。现代搜索技术的发展很多以提供优质、高效的 ... -
【串和序列处理 1】PAT Tree 子串匹配结构
2010-03-14 19:10 11247Patricia Tree 简称PAT tree ... -
【查找结构6】动态查找树比较
2010-03-12 13:32 11214我们这个专题介绍的动态查找树主要有: 二叉查找树(BST),平 ... -
【查找结构4】红黑树 [RBT]
2010-03-10 10:58 10494大部分转载:http://yanglongylj.blog.1 ... -
【查找结构5】多路查找树/B~树/B+树
2010-03-09 11:56 18099在前面专题中讲的BST、A ...
相关推荐
基于c语言实现。作为一个IBM的研究人员,请写一个程序找出给定的DNA片段之间的相同之处,使得对个体的调查相关联。 一个DNA碱基序列是指把在...给出一个DNA碱基序列的集合,确定在所有序列中都出现的最长的碱基序列
KMP算法,全称Knuth-Morris-Pratt字符串搜索算法,是一种线性时间复杂度的字符串匹配算法。它的主要思想是在发生不匹配时,能知道部分已经匹配的字符序列的后缀和模式串的前缀存在重复,因此可以利用这些信息避免...
KMP算法,即Knuth-Morris-Pratt算法,是一个线性时间复杂度的字符串匹配算法。它能在O(n+m)的时间复杂度内完成一个长度为n的文本串S和一个长度为m的模式串T的匹配工作,其中n和m分别代表文本串和模式串的长度。相比...
本科参加ACM竞赛的过程中积累下来的一部分算法模板,和自己在PKU上面做的一部分题目。 模板目录结构: 目录: 动态规划 O(n^2)的最长上升子序列 nlogn最长上升子序列 高精度 计算几何 Graham扫描法 两线段交点 凸...
2 8 字符串的最长回文子串:Manacher 算法 42 第 3 章 序列 44 3 1 网格中的最短路径 44 3 2 编辑距离(列文斯登距离45 3 3 最长公共子序列 47 3 4 升序最长子序列 49 3 5 两位玩家游戏中的必胜策略 52 第 4 章 数组...
11. 最大子串匹配 121 12. 最大子段和 122 13. 最大子阵和 123 常用源代码 包括很多经典算法 数学问题: 1.精度计算——大数阶乘 2.精度计算——乘法(大数乘小数) 3.精度计算——乘法(大数乘大数) 4.精度...
模式匹配(kmp) 逆序对数 字符串最小表示 最长公共单调子序列 最长子序列 最大子串匹配 最大子段和 最大子阵和 组合\ 排列组合生成 生成gray码 置换(polya) 字典序全排列 字典序组合 组合公式
抄袭检测 - 不同算法的比较分析用于抄袭检测的算法类型:子串匹配子序列匹配使用的算法:LCSS Rabin Karp KMP Boyer Moore Naive ========== LCSS 运行时间 O(mn) 子序列匹配使用的数据结构:2D Array HashMap =...
KMP字符串匹配: KMP字符串匹配,Linux源码中strstr函数的实现 二分查找: 二分查找,包括循环实现和非循环实现 矩阵链乘法: 计算矩阵相乘的最小次数以及输出如何相乘 最优二叉查找树: 求最优二叉查找树的期望搜索...
一.数论 4 1.阶乘最后非零位 4 2. 模线性方程(组) 4 3. 素数表 6 4. 素数随机判定(miller_rabin) 6 5. 质因数分解 7 6. 最大公约数欧拉函数 8 ...11. 最大子串匹配 121 12. 最大子段和 122 13. 最大子阵和 123
目录 一.数论 4 1.阶乘最后非零位 4 2. 模线性方程(组) 4 3. 素数表 6 4. 素数随机判定(miller_rabin) 6 5. 质因数分解 7 6. 最大公约数欧拉函数 8 ...11. 最大子串匹配 121 12. 最大子段和 122 13. 最大子阵和 123
算法,模板,ACM 十进制转任意进制 ...字符串KMP 凸包graham算法 输出最短路径 子集 拓扑排序 欧拉函数&素数筛选 Pick定理 高精度浮点数比较 日历 15数码是否有解 最大M子段和 MILLER_RABIN素性测试
串是由零个或多个字符组成的有限序列,又叫做字符串 串的逻辑结构和线性表很相似的,...这里主要讨论下字符串模式匹配的几种经典的算法:BF、BM、KMP BF(Brute Force)算法 Brute-Force算法的基本思想: 从目标串s 的
模式匹配(kmp) 逆序对数 字符串最小表示 最长公共单调子序列 最长子序列 最大子串匹配 最大子段和 最大子阵和 组合\ 排列组合生成 生成gray码 置换(polya) 字典序全排列 字典序组合 组合公式
10.11 最大子串匹配 204 10.12 最大子段和 205 10.13 最大子阵和 206 11.其它 207 11.1 大数(只能处理正数) 207 11.2 分数 212 11.3 矩阵 214 11.4 线性方程组 216 11. 5 线性相关 218 11.6 日期 219 11.7 读入 220 ...
这是我整理过的关于ACM题目常用到的算法代码,word文档,条理清晰,...6. 模式匹配(kmp) 7. 逆序对数 8. 字符串最小表示 9. 最长公共单调子序列 10. 最长子序列 11. 最大子串匹配 12. 最大子段和 13. 最大子阵和
13.6 模式匹配(kmp) 122 13.7 逆序对数 123 13.8 字符串最小表示 123 13.9 最长公共单调子序列 124 13.10 最长子序列 125 13.11 最大子串匹配 126 13.12 最大子段和 127 13.13 最大子阵和 127 14、 其它 128 14.1 ...
leetcode走方格起点到终点 LeetCode题目 动态规划,南大开放日2017年上机题。 中序遍历。 BST判断,中序遍历 交换节点,满足二叉搜索树。中序遍历的两种实现。...字符串匹配,kmp算法,得到匹配子串的个数 贪心算法
13.6 模式匹配(kmp) 122 13.7 逆序对数 123 13.8 字符串最小表示 123 13.9 最长公共单调子序列 124 13.10 最长子序列 125 13.11 最大子串匹配 126 13.12 最大子段和 127 13.13 最大子阵和 127 14、 其它 128 14.1 ...