首页 > 其他分享 >KMP

KMP

时间:2023-02-02 11:24:45浏览次数:53  
标签:匹配 前缀 后缀 next KMP 字符串

KMP总结

KMP:这三位学者发明的:Knuth,Morris和Pratt,所以取了三位学者名字的首字母。所以叫做KMP。
用途:字符串的匹配。

  • KMP算法的主要核心思想就是:记录已经匹配的信息,当出现不匹配时,能利用这些信息去避免从头进行匹配(暴力解法就是从头开始匹配)。

看到一个博主的思路,觉得很有用,就参考这位博主的文章,浅浅阐述一下KMP。

  • KMP算法的核心:是一个被称为部分匹配表(Partial Match Table)的数组。比如字符串"abababca"的PMT是这样的:
    img

模式串有8个字符,PMT就会有8个值。
KMP算法中,有一个重要的概念是字符串的前后缀,如果字符串A和B,存在A=BS,其中S是任意的非空字符串,那就称B为A的前缀。例如,”Harry”的前缀包括{”H”, ”Ha”, ”Har”, ”Harr”},我们把所有前缀组成的集合,称为字符串的前缀集合。后缀A=SB, 其中S是任意的非空字符串,那就称B为A的后缀,例如,”Potter”的后缀包括{”otter”, ”tter”, ”ter”, ”er”, ”r”},然后把所有后缀组成的集合,称为字符串的后缀集合。要注意的是,字符串本身并不是自己的后缀。
PMT的值的意思就是:字符串前缀合集和后缀合集中交集最长的元素长度。

  • 我们使用该表快速查找的方法就是:
    如下图所示:要在主字符串"ababababca"中查找模式字符串"abababca"。如果在 j 处字符不匹配,那么由于前边所说的模式字符串 PMT 的性质,主字符串中 i 指针之前的 PMT[j −1] 位就一定与模式字符串的第 0 位至第 PMT[j−1] 位是相同的。这是因为主字符串在 i 位失配,也就意味着主字符串从 i−j 到 i 这一段是与模式字符串的 0 到 j 这一段是完全相同的。而我们上面也解释了,模式字符串从 0 到 j−1 ,在这个例子中就是”ababab”,其前缀集合与后缀集合的交集的最长元素为”abab”, 长度为4。所以就可以断言,主字符串中i指针之前的 4 位一定与模式字符串的第0位至第 4 位是相同的,即长度为 4 的后缀与前缀相同。这样一来,我们就可以将这些字符段的比较省略掉。具体的做法是,保持i指针不动,然后将j指针指向模式字符串的PMT[j −1]位即可。
    img

简单点来说就是:如果在i处发生失配,那么前面肯定是相同的,但是怎么利用这个点呢,就找在模式串中前缀的交集,用模式串的前缀匹配字符串的后缀(前后缀交集的作用),可以节省大量的时间。
KMP算法中一般用next的数组实现快速匹配,next数组有很多种,有的会将next数组右移一位,将第一位设置为-1,有的也会保持原样,原本的PMT数组作为next数组,这样只是在生成的方式和后续匹配的方式有所区别,并没有实际的意义。
img
其寻找公共前后缀的方法我不多赘述,就是逐渐匹配就行
其代码实现如下:

void getNext(vector<int> &next, string needle) {
        int j = 0;
        next[0] = j;
        for (int i = 1; i < needle.size(); i++) {
            while (j > 0 && needle[j] != needle[i]) {
                j = next[j - 1];//next数组不一样,这里的赋值不一样
            }
            if (needle[j] == needle[i]) {
                j++;
            }
            next[i] = j;//继承已经匹配的模式串字串
        }
        
    }

其中需要注意的是,i代表的是后缀的位置,j在代表前缀的同时也代表的是具有最长公共前后缀的长度,所以j的值可以赋给next。
匹配成功:将之前的结果传递
匹配不成功:匹配不成功,需要一直回等待匹配成功或者一直回退到0。
next数组中存储的最长相同前后缀的长度是一位位比较出来的,所以前面如果出现匹配不成功,需要一步步退回到0或者匹配成功为止;如果比较成功,则下一次可以继承上一次比较结果,进行判断。
参考:海纳代码随想录

标签:匹配,前缀,后缀,next,KMP,字符串
From: https://www.cnblogs.com/zhaowenrui-life/p/17085403.html

相关文章

  • KMP
    #include<iostream>#include<string.h>#include<stdio.h>#include<fstream>usingnamespacestd;intnext[10];voidNext(char*T,intn){inti=1,j=0;nex......
  • KMP算法
    1-从oneNote上搬来2-代码String数据结构//串的堆分配存储结构(malloc占用的是堆空间)structHString{char*ch;//若是非空串,则按串长分配存储区;否则ch为NULL......
  • 扩展kmp
    扩展kmp是用来解决字符串b与字符串a的各个后缀的最长公共前缀的问题。题目参考:洛谷P5410算法思路:设\(nxt[i]\)为b以第i个字符为头的后缀,\(nxtb[i]\)为a以第i个字符为头......
  • KMP字符串匹配问题
    KMP算法本文参考资料:https://www.zhihu.com/question/21923021KMP算法是一种字符串匹配算法,可以在\(O(n+m)\)的时间复杂度内实现两个字符串的匹配。字符串匹配问题首......
  • hdu:Simpsons’ Hidden Talents(kmp)
    ProblemDescriptionHomer:Marge,Ijustfiguredoutawaytodiscoversomeofthetalentsweweren’tawarewehad.Marge:Yeah,whatisit?Homer:Takemefor......
  • hdu:剪花布条(kmp)
    ProblemDescription一块花布条,里面有些图案,另有一块直接可用的小饰条,里面也有一些图案。对于给定的花布条和小饰条,计算一下能从花布条中尽可能剪出几块小饰条来呢?Input......
  • 把KMP算法嚼碎了才利于消化!(C++)
    相信不少人在学数据结构的时候都被KMP算法搞的迷迷糊糊的,原理看的似懂非懂,代码写不出来,或者写出来了也不知道为什么就可以这么写。本文力求尽可能通俗详细的讲解KMP算法,让......
  • KMP 详解
    简介KMP这个名字的由来:它是三个人:D.E·Knuth、J.H·Morris和V.R·Pratt同时发现的。KMP是一种字符串单模匹配算法,复杂度\(\operatorname{O(n+k)}\)。其中......
  • KMP算法详解(逻辑分析&数学证明&代码实现)
    前言KMP算法是Knuth、Morris、Pratt三人在BF算法的基础上同时提出的模式匹配的高效算法。本文以字符串匹配问题为例,以通俗易懂的语言对KMP算法进行逻辑分析、数学证明和代码......
  • C++ 算法进阶系列之从 Brute Force 到 KMP 字符串匹配算法的优化之路
    1.字符串匹配算法所谓字符串匹配算法,简单地说就是在一个目标字符串中查找是否存在另一个模式字符串。如在字符串ABCDEFG中查找是否存在EF字符串。可以把字符串ABCDE......