`
huntfor
  • 浏览: 201290 次
  • 性别: Icon_minigender_1
  • 来自: 杭州
社区版块
存档分类
最新评论

KMP算法(1)——java实现

 
阅读更多

这篇博文写的实在是太糟蹋了,请大家移步KMP算法小结,如果未能帮大家解惑,请见谅,并欢迎再新博文下面留言讨论。

 

KMP是比较知名的一个字符串匹配算法。由D.E.Knuth与V.R.Pratt和J.H.Morris同时发现(不明白什么叫同时发现+_+)因此得名KMP算法。

 

首先大家想一下字符串如何匹配?

比如str1 = “BBC ABCDAB ABCDABCDABDE”,想知道这个字符串中是否包含str2 = “ABCDABD”。

逗逼:“这尼玛欺负我不会拼contains吗?”回答正确。但是contains的实现是怎样的?不用看源码,先自己想一下有木有思路。

一个简单直接的思路是:从str1第1个字母开始匹配,如果成功,good,匹配第2个...直到结束或者第i个字母不相等,然后从str2的第2个字母开始匹配....

是的,JDK源码就是这么做的。详见Implement strStr

这个方法是暴力算法,也可以说回溯。一般而言,暴力算法往往都不是最优的。KMP算法即是字符串匹配的优化算法。

本博文主要先讲一下KMP算法为什么比暴力算法更优。

 

在这之前,先给大家普及两个概念:前缀 & 后缀。

拿一个例子来讲:“china”

前缀::“c”,“ch”,“chi”,“chin”

后缀:"a","na",“ina”,"hina"

不知道大家有没有看明白,

所谓前缀就是str.substring(0,n) —— 其中n从1 ~ str.length() - 1(n == 0时,返回一个空串,不算前缀)

所谓后缀就是str.substring(m)——其中m从1 ~ str.length()-1

 

接下来的部分整理自网络日志,感谢原作者。

 

看下面两个字符串

【我们采取Implement strStr中的定义,将上面的字符串称为haystack,下面的称为needle】

B与A不匹配,haystack后移一位,得到:

 

还是不匹配,继续后移:直到:

good,匹配成功,然后匹配下面needle的第2个字符。

B和B,还是相同,一直匹配,直到:

按照我们之前的暴力做法,看到D匹配失败之后,就回溯到:

继而从B往下匹配,相当于haystack的指针往后回溯了。这肯定是对的,但是每次needle不能完全匹配时,都需要回溯,因此最坏的时间复杂度是n*m

 

接下来看下KMP是怎么做到不回溯的

我们继续回到回溯前的这一刻:

虽然匹配到D时,匹配失败了,但是我们知道了之前的ABCDAB是成功匹配的,暴力算法没有用到这些信息。KMP算法即设法利用这些信息,并不能让needle 和 haystack无需回溯。从而提升效率。

 

要做到这一点,需要用到Partial match table——部分匹配表

至于该表怎么求的,一会儿再讲

 

好,再回到刚才的状态

D(下标为 j )与空格(下标设为 i )匹配失败,前面ABCDAB是匹配的,匹配长度为length(本例是6),查表得B(要查失配字母的前一个字母,或者最后一个匹配的字母)对应的value为2,因此我们将needle前移length - 2 位【代码是将 j 的值减去length - 2(本例是4位)】即得到

PS:插播一下上面的移动位数的计算公式
moveStep = partial_match_length  -  table[partial_match_length - 1]

 

看到这里是不是有点明白了,移动之后 空格 之前的AB是匹配好的。

这里KMP算法耍了一个小聪明,首先,我们看到AB是match的字符串ABCDAB的一个前缀,但是也是一个后缀,而这个前缀和后缀是相等的,对于haystack字符串而言,空格之前的AB本来是匹配后缀的,然后,我们将前缀移动过来跟它匹配,有点 x = y && y = z 得到 x = z 的感觉。

解释:x(前缀) = y(后缀) && y = z(后缀与haystack匹配)  =>  x = z(前缀也可以和haystack匹配)

从而无须将指针回溯,肯定有人会问,这样直接跳过会不会漏掉中间的情况,答案当然是否定的。

提示一下,我们当时选:前缀==后缀时,选的是最长的,比如aaaa,满足条件的最长前缀(后缀)是aaa。

 

言归真正,空格 与C 还是不匹配的,match的字符串(AB)长度length == 2,而C前的B在Partial match table中的value为0,因此我们需要将needle前移动length - 0(即2位)得到

 

 

这种情况比较简单,haystack后移:

重复上述步骤,发现:这下发了。。。一直匹配到D才适配,这次needle移多少位呢?且看D的前的B的value为2,match的length = 6.因此前移4位,得到

然后继续往下匹配。找到一个!如果想继续找下去,查看D的value值 == 0,match的length == 7,则移动7位。跟之前的一样。

 

 

Partial match table——部分匹配表

首先来看PMT中的value的意义:

还以刚才的字符串needle为例

A的value为0,表示以字符串A,相等的前缀和后缀中,最大长度为0,显然,单字符压根就没有前后缀

B的value为0,表示字符串AB,它只有一个前缀:A,一个后缀B,不存在相等的前缀,后缀,因此=0

来看第二个B,表示字符串ABCDAB,它有一个前缀AB,同时也有一个后缀AB,长度为2,因此value=2

 

这样讲应该很明白了吧,上文中还举了一个例子“aaaa”

它的PMT应该是这样的

a a a a
0 1 2 3

第一个a,肯定value为0

第二个a,表示字符串aa,有一个前缀a,一个后缀a,因此value = 1

第三个a,表示字符串aaa,有前缀a,aa。有后缀aa,a,因此相等的最长前缀后缀应该是aa,value=2

 

 

最简单的代码实现如下:

	public static int[] getPartialMatchTable(String s) {
		if (s == null) {
			return null;
		}
		int length = s.length();
		int[] value = new int[length];
		value[0] = 0;
		for (int i = 1; i < length; i++) {
			String tem = s.substring(0, i + 1);
			int prefixEnd = i;
			int suffixBegin = 1;
			String prefix;
			String suffix;
			while (prefixEnd > 0) {
				prefix = tem.substring(0, prefixEnd);//取前缀
				suffix = tem.substring(suffixBegin);//取后缀
				if (prefix.equals(suffix)) {
					value[i] = prefixEnd;
					break;
				} else {
					prefixEnd--;
					suffixBegin++;
				}
			}
		}
		return value;
	}

 有了PMT,KMP算法实现起来就会容易地多了

  • 大小: 5.3 KB
  • 大小: 5.4 KB
  • 大小: 5.7 KB
  • 大小: 5.6 KB
  • 大小: 5.3 KB
  • 大小: 6.1 KB
  • 大小: 5.3 KB
  • 大小: 8.8 KB
  • 大小: 5.3 KB
  • 大小: 5.5 KB
  • 大小: 5.5 KB
  • 大小: 5.6 KB
  • 大小: 5.2 KB
  • 大小: 8.8 KB
  • 大小: 5.6 KB
分享到:
评论

相关推荐

    KMP.rar_KMP_KMP算法_串 KMP算法_字符串匹配

    KMP算法的代码实现通常使用C++、Java、Python等编程语言,代码简洁且易于理解,是算法学习的经典案例。 总的来说,KMP算法以其高效性和广泛的应用性,成为字符串匹配领域不可或缺的一部分。通过理解和掌握KMP算法,...

    数据结构王道考研2023年KMP串匹配算法C++/Java实现

    总的来说,掌握KMP算法及其C++和Java实现对于提升你的编程技能和应对考研中的数据结构题目至关重要。通过深入学习和不断练习,你将能够更高效地处理字符串匹配问题,为未来的学术和职业发展打下坚实基础。

    经典算法问题的java实现<二>

    如果代码涉及字符串处理,那么它可能实现了KMP算法。 5. **动态规划**:动态规划是一种解决复杂问题的有效方法,通过将问题分解为更小的子问题来求解。例如,Fibonacci数列可以通过动态规划实现,避免重复计算。 6...

    Java KMP算法实现(源代码)

    ### Java 实现 KMP 算法详解 #### KMP 算法概述 KMP 算法是由 Donald Knuth、James H. Morris 和 Vaughan Pratt 共同发明的一种高效字符串匹配算法。它通过预处理模式串来提高匹配效率,避免了传统模式匹配算法在...

    各种算法的java实现

    10. **字符串处理**:Java中的String类提供了丰富的操作方法,如模式匹配、替换、分割等,涉及到KMP算法、Boyer-Moore算法等字符串匹配策略。 在《各种算法java实现.docx》这个文档中,你可能会找到以上算法的详细...

    KMP算法求next 和 nextval

    KMP算法通常用C++、Java等编程语言实现,其主要逻辑包括构建next数组、主函数中的匹配过程。这里我们给出一个简单的Python实现示例: ```python def compute_next(pattern): next = [0] j = -1 for i in range(1...

    如何通过Java代码实现KMP算法

    "如何通过Java代码实现KMP算法" KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。KMP算法的关键是利用匹配失败后...

    我的LeetCode和剑指offer刷题源码——Java版.zip

    标题 "我的LeetCode和剑指offer刷题源码——Java版.zip" 提示这是一个包含Java编程语言实现的解题代码库,主要针对两个知名的在线编程挑战平台:LeetCode和剑指Offer(也称为《程序员面试金典》)。LeetCode是一个...

    经典常用算法 Java和C语言两种实现

    本资源“经典常用算法 Java和C语言两种实现”聚焦于将这些算法用两种广泛使用的编程语言——Java和C语言进行实现,旨在帮助开发者理解和应用这些基础且重要的算法。 1. **排序算法**: - **冒泡排序**:简单的比较...

    数据结构与算法分析-Java语言描述

    《数据结构与算法分析——Java语言描述》是一本深度探讨数据结构和算法的书籍,它以Java编程语言为载体,详细阐述了各种重要的数据结构及其相关的算法实现。这本书对于计算机科学的学习者,尤其是软件开发者来说,是...

    java经典算法题

    除此之外,还有字符串匹配算法,如KMP算法和Boyer-Moore算法,用于在文本中快速查找特定模式。在数据结构方面,栈、队列、链表、树、图等都是算法实现的基础,如平衡二叉搜索树(AVL树、红黑树)在数据库索引和搜索...

    JAVA算法深层解析

    《Java算法第6章.ppt》可能专门讨论了字符串处理的算法,如KMP算法、Rabin-Karp算法,这些都是在文本处理和搜索问题中常见的技术。 《Java算法第7章.ppt》和《Java算法第8章.ppt》可能涉及到组合数学和概率论在算法...

    java各种经典算法大全 还包括C语言的实现

    本资源“java各种经典算法大全 还包括C语言的实现”涵盖了两个广泛使用的编程语言——Java和C,它们在实现算法方面各有特点。下面,我们将深入探讨这些经典算法以及它们在两种语言中的实现方式。 1. **排序算法**:...

    Java语言的数据结构与算法书

    《数据结构与算法分析——Java语言描述.pdf》这本书将涵盖以上所有内容,并通过实例和练习帮助读者巩固理解。学习这些知识不仅可以提升编程技能,也能为面试和项目开发做好准备。记住,理解并熟练运用数据结构和算法...

    kmp.rar_数值算法/人工智能_Java__数值算法/人工智能_Java_

    1. **KMP算法**: KMP(Knuth-Morris-Pratt)算法是一种高效的字符串搜索算法,由唐纳德·克努斯、詹姆斯·莫里斯和维诺德·普拉特于1977年提出。它避免了对已知模式的重复比较,显著提高了效率。KMP算法的核心是...

    java算法4jar

    这两个核心的jar包——stblib.jar和algs4.jar,包含了实现各种经典算法的类库,是理解并实践算法的重要工具。 stblib.jar库主要是为了解决算法四中涉及的稳定性和排序问题。稳定性在排序算法中是一个关键概念,它...

    多种编程语言的算法集合。_C++_Java_下载.zip

    《多种编程语言的算法集合——C++与Java的探索》 在编程的世界里,算法是解决问题的核心工具,它们是程序员的智慧结晶,是程序设计的灵魂。这个名为"多种编程语言的算法集合。_C++_Java_下载.zip"的压缩包文件,...

    牛客网算法基础和进阶资源

    三、编程语言实战——Java 作为标签之一,Java 是实现算法的重要工具。熟悉 Java 的基本语法、类库以及面向对象特性对于算法实现至关重要: 1. **Java 数据结构实现**:理解如何用 Java 实现上述的数据结构,例如用...

    Java || c || c++经典算法

    本资源“Java || c || c++经典算法”集合了三种编程语言——Java、C和C++的算法实现,旨在帮助编程爱好者深入理解和掌握算法设计与实现。 Java是一种广泛使用的面向对象的编程语言,其强类型、自动内存管理以及丰富...

Global site tag (gtag.js) - Google Analytics