KMP算法学习笔记

来源:互联网 发布:java runnable 编辑:程序博客网 时间:2024/05/17 21:41


KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。(百度的嘻嘻)

KMP难在对于next数组的构建与理解

next[i]的定义是 到 i 处已找到的最长相同前后缀的长度

next的作用是当字符串s1和字符串s2匹配到s1[i]和s2[j]时, 若s1[i]和s2[j]不相等,就不必再把j重新从0开始找,而是跳到和当前指针j有相同前缀的地方。

s1[i]和s2[j]不相等,但之前有一部分是相同的

举个例子:比如说 ababc 和 ababd, 比较到c和d时发生了冲突,但这时发现d的前面有一个ab, c的前面也有一个ab,这时候我们只要跳到前一个ab处就可以继续比较

ababc ababd 中的 c和a了, 省了不少时间


首先我们要理解一波前缀和后缀, 前缀和后缀指的是一个集合

例如  ababa

其前缀为{a,ab,aba,abab}(不包括最后一个)

后缀为{a,ba,aba,baba}(不包括第一个)

可以很清楚的看到,最长前后缀就是 aba, 长度为3

我个人理解的next[i]是跳到与i的后缀 有最长的相同前缀的地方

贴一份next数组构建的代码, 也就是s2的自我匹配


for(i = 1; i < bn; i++){while(j && s2[j]!=s2[i]) j = next[j-1];//指针跳到j-1的最长前缀处//s2[j]!=s2[i],但是既然j>0,说明从s2[0]到s2[j-1]==s2[i-j]到s2[i-1],这时跳到新的j,新的s[j-1]也会等于原来的s[j]if(s2[j]==s2[i]){next[i] = ++j;//next[i] = 当前指针(因为字符串是从0开始的,而指针到j最长前缀为j-1)+1, 同时 j往下移一个指针} }然后贴出完整代码:#include <cstdio>#include <cstring>using namespace std;int next[1001];char s1[1000001], s2[1001];//next[i]指 到 i 处的最长前后缀 int main(){    int i, j = 0, an, bn;    scanf("%s%s", s1, s2);    an = strlen(s1); bn = strlen(s2);    for(i = 1; i < bn; i++){        while(j && s2[j]!=s2[i]) j = next[j-1];//指针跳到j-1的最长前缀处        //s2[j]!=s2[i],但是既然j>0,说明从s2[1]到s2[j-1]==s2[某个位置开始]到s2[i-1],这时跳到新的j,新的s[j-1]也会等于原来的s[j]        if(s2[j]==s2[i]){            next[i] = ++j;//next[i] = 当前指针(因为字符串是从0开始的,而指针到j最长前缀为j-1)+1, 同时 j往下移一个指针        }     }    j = 0;    for(i = 0; i < an; i++){        while(j  && s1[i] != s2[j]){            j = next[j-1];//如果目前的s1[i]和s2[j]不相等就一直跳到最长前缀处, 直到相等就接着查找         }        if(s1[i] == s2[j]) j++;//相等的话就移动s2[]的指针         if(j == bn){            printf("%d\n", i-j+2);//在第几个字母找到的             j = next[j-1];//跳到上一个位置的next处,这样可以下次直接比较s1[i]和s2[j]         }        }    for(i = 0; i < bn; i++) printf("%d ", next[i]);    return 0;}可以去B站搜索KMP算法,印度小哥讲的超级详细链接:https://www.bilibili.com/video/av3246487/?from=search&seid=17380554719454557667

原创粉丝点击