【算法】字符串匹配之KMP算法

KMP算法的Java实现(基于阮一峰的博客) 这个算法也看了大半天了,仔细看过两个人的博客,一个是传说中的Matrix67,另一个是阮一峰,个人感觉阮一峰的非常好理解,但是和百度其他人的做法有些出入,不过仍然是首选。Matrix67大神的也还可以,就是P[]的解释太复杂了,一整段文字带符号看得人欲仙欲死。 下面是两人的链接: http://kb.cnblogs.com/page/176818/ http://www.matrix67.com/b 阅读详情

对于字符串匹配,暴力法是对每个位置进行逐位匹配,只要有匹配失败的,就从待匹配串的下个位置开始从头匹配,这样的时间复杂度是O(MN)。
KMP算法能解决这样效率低下匹配,其核心思想是保留已匹配的前缀和,避免重复匹配,时间复杂度是O(M+N)。

举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"?

  1. 首先,字符串"BBC ABCDAB ABCDABCDABDE"的第一个字符与搜索词"ABCDABD"的第一个字符,进行比较。因为B与A不匹配,所以搜索词后移一位。
  2. 因为B与A不匹配,搜索词再往后移。
  3. 直到字符串有一个字符,与搜索词的第一个字符相同为止。
  4. 接着比较字符串和搜索词的下一个字符,还是相同。
  5. 直到字符串有一个字符,与搜索词对应的字符不相同为止。
  6. 这时,如果使用暴力法,将搜索词整个后移一位,再从头逐个比较。这样做虽然可行,但是效率极低,因为把"搜索位置"移到已经比较过的位置,重比一遍。
  7. 当空格与D不匹配时,其实知道前面六个字符是"ABCDAB"。KMP算法的想法是,设法利用这个已知信息,不要把"搜索位置"移回已经比较过的位置,继续把它向后移,这样就提高了效率。
  8. 可以针对搜索词,算出一张《部分匹配表》(Partial Match Table)。
  9. 已知空格与D不匹配时,前面六个字符"ABCDAB"是匹配的。查表可知,最后一个匹配字符B对应的"部分匹配值"为2
    在这里插入图片描述
  10. 因为空格与C不匹配,搜索词还要继续往后移。这时,已匹配的字符数为2(“AB”),对应的"部分匹配值"为0。所以,移动位数 = 2 - 0,结果为 2,于是将搜索词向后移2位。
    在这里插入图片描述
  11. 因为空格与A不匹配,继续后移一位。
  12. 逐位比较,直到发现C与D不匹配。
    在这里插入图片描述
  13. 逐位比较,直到搜索词的最后一位,发现完全匹配,于是搜索完成。

    "部分匹配值"就是"前缀"和"后缀"的最长的共有元素的长度。

以"ABCDABD"为例,

  • "A"的前缀和后缀都为空集,共有元素的长度为0;
  • "AB"的前缀为[A],后缀为[B],共有元素的长度为0;
  • "ABC"的前缀为[A, AB],后缀为[BC, C],共有元素的长度0;
  • "ABCD"的前缀为[A, AB, ABC],后缀为[BCD, CD, D],共有元素的长度为0;
  • “ABCDA"的前缀为[A, AB, ABC, ABCD],后缀为[BCDA, CDA, DA, A],共有元素为"A”,长度为1;
  • “ABCDAB"的前缀为[A, AB, ABC, ABCD, ABCDA],后缀为[BCDAB, CDAB, DAB, AB, B],共有元素为"AB”,长度为2;
  • "ABCDABD"的前缀为[A, AB, ABC, ABCD, ABCDA, ABCDAB],后缀为[BCDABD, CDABD, DABD, ABD, BD, D],共有元素的长度为0。

KMP算法的Java实现

class Main {
    public int KMP(String s1, String s2){
        if(s2.length()>s1.length() || s2.length()==0) return -1;
        int i=0,j=0;
        int[] next = getNextArray(s2);
        while(i<s1.length()){
            if(s1.charAt(i)==s2.charAt(j)){
                i++;
                j++;
                if(j==s2.length()) return i-j;
            }else{
                if(next[j]==-1) i++;
                else j=next[j];
            }
        }
        return -1;
    }
    public int[] getNextArray(String s){
        int[] next = new int[s.length()];
        next[0]=-1;
        for(int i=1;i<s.length();i++){
            int j=next[i-1];
            while(j!=-1){
                if(s.charAt(i-1) == s.charAt(j)){
                    next[i]=++j;
                    break;
                }else j=next[j];
            }
        }
        return next;
    }

}
KMP算法的时间复杂度 在学习程杰老师的大作《大话数据结构》时,遇到KMP算法始终没有看明白, 在网上搜索后找到并阅读了阮一峰老师对KMP算法的解释后,茅塞顿开,便按照文章思想编写了算法代码, 算法代码链接:http://blog.csdn.net/register_man/article/details/75012461  但是,当计算算法的时间复杂度时,遇到了问题,发现在获得next数组时的时间复杂度远远超过预 阅读详情

相关推荐

KMP算法:线性时间O(n)字符串匹配算法

算法导论》一书中有一句话,我认为说的非常透彻:“这两个程序有很多相似之处,因为它们都是一个字符串对模式P的匹配KMP-MATCHER是文本T针对模式P的匹配,COMPUTE-PREFIX是模式P针对自己的匹配。”

机器学习 3114

kmp算法(转自博客园 作者:阮一峰 )

字符串匹配是计算机的基本任务之一。   举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"?   许多算法可以完成这个任务,Knuth-Morris-Pratt算法(简称KMP)是最常用的之一。它以三个发明者命名,起头的那个K就是著名科学家Donald Knuth。   这种算法不太容

qq_27254841的博客 1437

经典字符串匹配算法——KMP算法

KMP算法 KMP算法是一种高效的字符串匹配算法,在传统暴力遍历匹配的基础上做了一定的优化。 首先KMP算法的实现也是使用了回退思想,不过与暴力遍历不同,KMP的回退,是让子串进行匹配,而不是主串。 KMP示例 首先我们来看两个例子来理解KMP算法: 例1: 分别从str的i和sub的j位置处开始匹配: 此时a与c不匹配,如果暴力遍历的话,是i回到到b,j也回到a,重新一轮匹配。而KMP算法,是将子串的j回到第二个a,str[i]与sub[j]重新开始匹配。原因很明显,第二个ab与第一个ab是相同的,因

aaaaaaaWoLan的博客 1万+

KMP模式匹配算法(转自阮一峰)

通俗易懂的KMP模式匹配算法的原理

一只不开窍的笨鸟 2078

字符串模式匹配算法——KMP算法

字符串是一种常见的数据结构,它由一个字符序列组成,可以被视为字符的数组或列表。每个字符都有一个对应的索引位置,允许对字符串进行访问、修改和操作。对于字符串而言,寻找字符串中子串的位置是最重要的操作之一,查找子串位置的操作通常称为。

m0_73609199的博客 3710

字符串匹配——KMP算法

字符串匹配——KMP算法字符串匹配是计算机编程中最常使用到的基础算法之一。字符串匹配相关的算法很多,Knuth-Morris-Pratt(KMP算法是最常用的之一。最近在学习KMP算法,学习了许多相关的博客,记录一下,以备日后不会写了回来看看。 ​ KMP算法有两个要点:1)部分匹配 和next数组的计算;2)利用部分匹配表解决字符串匹配问题。 1、KMP算法原理 (1)原理 ​ 给定两个字符串:文本串S="BBC ABCDAB ABCDABCDABDE"和模式串P="ABCDABD",要求找

哦豁灬 2万+

字符串匹配算法KMP

目录需求基础知识逻辑解析源码实现 需求 先简单描述溪源曾经遇到的需求: 需求一:项目结果文件中实验结论可能会存在未知类型、转换错误、空指针、超过索引长度等等。这里是类比需求,用日常开发中常出现的错误类型作为需求,如果要以上结论则判断这个项目检测失败; 解决方案一: 大家常用的方式可能是if(){continue;} esle if (){continue;} …或者switch-case等; 方案二:可能会使用集合contain()方法; 方案三:依次匹配字符串中字符(暴力匹配); 以上两种方案都能解决;然

增量星球 4787

字符串匹配——KMP算法【C语言】

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n) 一、暴力算法 int BF(char *chang,char *duan) { int c_strlen=strle...

weixin_45423515的博客 7456

字符串匹配算法KMP详解

本人是普通本科院校的一名大二学生,为提高自身能力特地锻炼自己发表一些文章,题解等, 望各位大佬能够对我这个菜鸟所做多多指正,在此谢过各位啦~~~ 文章的开始,我想向KMP算法的三位创始人Knuth,Morris,Pratt致敬,如此思维之精妙,堪称大神。 KMP算法字符串匹配算法中一个很重要的算法KMP算法的作用是在一个字符串中寻找子串的位置,也叫串的模式匹配。如主串s="aaabbaab",子串t(也叫模板串)="aab",要寻找aab在主串中的位置。 字符串匹配的暴力做法就是分别将两个指针i,

qq_51502732的博客 4647

字符串匹配KMP算法

这种类型字符串题目都可以采用暴力解法,套两层for循环也可以实现,但是时间复杂度太大,采用KMP算法之后,时间复杂度更低。所以掌握KMP算法还是有意义的

Hhjhj255的博客 866

KMP 字符串匹配算法

都说KMP算法难,我说KMP算法真不难,不信你点进来看看。

qq_63943454的博客 1055

KMP字符串匹配算法

字符串匹配算法朴素字符串匹配算法Rabin-Karp算法有限自动机KMP算法 朴素字符串匹配算法 Rabin-Karp算法 有限自动机 KMP算法 KMP算法是Knuth,Morris和Pratt三人设计的线性时间字符串匹配算法。不管是网上还是书上介绍的这个算法都很复杂,让人看了头都麻了,但是它的算法思路是很简单的,就是尽可能地利用已知的信息,从而减少尝试匹配的次数。 什么叫尽可能地利用已知的信息呢? 假设我们有字符串T,要在T中匹配字符串P。 假如匹配进行到如下图的过程,从T的第5个字符a开始的后五个字

m0_63989537的博客 1045

Java用KMP算法解决字符串匹配问题

14.4 KMP 算法 14.4.1 应用场景-字符串匹配问题 字符串匹配问题: 有一个字符串 str1= “迪丽热巴 迪丽热巴你你好 迪丽迪丽热巴迪丽热巴你好”,和一个子串 str2=“迪丽热巴你好” 现在要判断 str1 是否含有 str2, 如果存在,就返回第一次出现的位置, 如果没有,则返回-1 先看一下暴力匹配法(不是KMP算法,用暴力匹配KMP算法做对比) 如果用暴力匹配的思路,并假设现在 str1 匹配到 i 位置,子串 str2 匹配到 j 位置,则有: 如果当前字符匹配成功(即 s

当一个合格的软件工程师 2738

kmp算法 php 阮一峰,KMP算法 理解与实现

KMP算法,背景不必多说,主要想写一写自己对KMP算法的一些理解和其具体实现。关于KMP算法的原理,阮一峰老师的这篇文章足矣。文中对KMP算法匹配过程以及“部分匹配表”具体代表什么,都解释的十分简洁明了,看过之后也算是对KMP算法有了一个直观的了解。下面我想就算法的具体实现,尤其是“部分匹配表”的生成(个人认为KMP算法实现中,最不容易理解的部分),进行一些分析。KMP算法具体实现KMP算法的主...

weixin_39826971的博客 522

最通俗易懂的求next数组的方法(KMP算法

一、字符串匹配KMP算法 相信小伙伴们看了阮一峰老师讲解的KMP算法后也会有醍醐灌顶的感觉。可惜,阮老师没有去讲如何求部分匹配表(Partial Match Table),但这也是写出KMP算法的关键所在。所以,我打算再详细讲讲如何求部分匹配表,也即next数组。 二、求部分匹配表(next数组) 1.部分匹配值 ①前缀 1个字符串除去末尾字符,以首字符开头的所有子串。 ②后缀 1个字符串除去首字符,以末尾字符结尾的所有子串。 比如:字符串:ABCDAB 前缀:A、AB、ABC、ABCD、ABCDA

南七行者的博客 1万+

字符串匹配KMP算法

作者: 阮一峰 日期: 2013年5月 1日 字符串匹配是计算机的基本任务之一。 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"? 许多算法可以完成这个任务,Knuth-Morris-Pratt算法(简称KMP)是最常用的之一。它以三个发明者命名,起头的那个K就是著名科学家Don

ahuang1900的专栏 549

KMP算法-从头到尾彻底理解KMP

一:背景 给定一个主串(以 S 代替)和模式串(以 P 代替),要求找出 P 在 S 中出现的位置,此即串的模式匹配问题。 Knuth-Morris-Pratt 算法(简称 KMP)是解决这一问题的常用算法之一,这个算法是由高德纳(Donald Ervin Knuth)和沃恩·普拉特在 1974 年构思,同年詹姆斯·H·莫里斯也独立地设计出该算法,最终三人于 1977 年联合发表。 在继...

橘嘉禾 747

算法KMP算法原理分析

KMP算法KMP算法简介一般字符串匹配算法KMP算法原理代码实现 KMP算法简介   KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。   一般的字符串匹配算法算法在子串中有多个字符和模板串中的若干个连续字符比较都相等,但最后一个字符比较不相等时,模板串和子串的比较位置都需要回退,而KMP算法在上述情况下,模板串位置不需要回退,从而可以大大提高效率   KMP算法的核心是利用子串匹配失败后

这道题我不会做...不会做啊..太难了!! 1061
上一篇: 布隆过滤器
下一篇: 【操作系统】select、poll和epoll详解
Steven_L_
博客等级 码龄7年 5粉丝 49原创
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值