1、KMP是一种用来进行字符串匹配的算法,首先我们来看一下普通的匹配算法:


现在我们要在字符串ababcabcacbab中找abcac是不是存在,那么传统的查找方法就是一个个的匹配了,如图:

经过六趟匹配之后,终于匹配上了。现在是数据比较小的时候,大家可能没有什么感觉,如果我们的数据是百万级别的,那用这种方法无疑复杂度太高了,很难接受。

2、模式匹配的一种改进算法:


这种改进算法由D.E.Knuth与V.R.Pratt和J.H.Morris同时发现的,因此人们称他为克努特-莫里斯-普拉特操作(简称KMP算法)。此算法可以在O(n + m)的时间数量级上完成串的模式匹配操作。其改进在于:每当一趟匹配过程中出现字符比较不等时,不需要回溯i指针,而是利用已经得到的“部分匹配”结果将模式向右“滑动”尽可能远的一段距离后,继续进行比较。下面先从具体的例子看起。

回顾上面的传统的匹配过程,在第三趟的匹配中,当i = 7、j = 5字符比较不等时,又从i = 4、j = 1重新开始比较。然后,经仔细观察发现,在i = 4和j = 1,i = 5和j = 1以及i = 6和j = 1这3次比较都是不必进行的。因为从第三趟部分比配结果就可得出,主串中第4、5和6个字符必然是'b'、'c'和'a'(即模式串中的第2、3、和4个字符)。因为模式中的第一个字符是a,因此它无需再和这3个字符进行比较,而仅需要将模式串向右滑动3个字符的位置继续进行i = 7、j = 2时字符比较即可。同理,在第一趟匹配中出现字符不等时,仅需要将模式向右移动两个字符的位置继续进行i = 3、j = 1时的字符比较。由此,在整个匹配过程中,i指针没有回溯,如图4.4所示。

3、KMP


此时我们构建一个next[]数组,这个数组的意思就是,当主串中的第i个字符与模式串中的第j个字符失配时,模式串中的next[j]个字符与第i个字符继续进行比较,显然复杂度提高了很多。

匹配代码:

int index_KMP()

{

    int stra = strlen(a);

    int strb = strlen(b);

    int i = -,j = -;

    while(i < stra && j < strb)

    {

        if(j == - || a[i] == b[j])

        {

            i++;j++;

        }

        else

        {

            j = next[j];

        }

    }

    if(j >= strb)

    {//在a中找到了b字符串

        return ;

    }

    return ;

}

4、求next数组:


KMP算法实在已知模式串的next函数值的基础上执行的,那么,如何求得模式串的next函数值呢?

从上述讨论可见,此函数值仅取决于模式串本身和相匹配的主串无关。我们可从分析其定义出发用地推的方法求得next函数值。

设next[j] = k,这表明在模式串中存在下列关系:'p1....pk-1' = 'pj-k+1....pj-1'。其中k为满足1 < k < j的某个值,此时的next[j + 1] = ?可能有两种情况:

(1)若pk = pj,则表明模式串中'p1....pk' = 'pj-k+1....pj'

这就是说next[j+1] = k+1,即next[j + 1] = next[j] + 1。

(2)若pk != pj,则表明在模式串中‘p1....pk’ != 'pj-k+1....pj'

此时可把求next函数值的问题看成是一个模式匹配的问题,整个模式串既是主串又是模式串,而当前在匹配过程中,已有pj-k+1=p1,pj-k+2=p2,...,pj-1=pk-1,则当pj!=pk时应将模式向右滑动至模式中的第next[k]个字符和主串的第j个字符相比较。若next[k] = k',且pj = pk',则说明在主串中的第j+1个字符之前存在一个长度为k’(即next[k])的最长子串,和模式串中从首字符起长度为k'的子串相等,即'p1...pk'' = 'pj-k+1...pj'   (1 < k' < k < j)      (4 - 10)

这就是说next[j + 1] = k' + 1即next[j + 1] = next[k] + 1。

同理,若pj!=pk',则将模式继续向右滑动直至将模式中第next[k']个字符和pj对齐,....,依次类推,直至pj和模式中某个字符匹配成功或者不存在任何k'(1 < k' < j)满足等式(4 - 10) 则next[j + 1] = 0。

代码:

void get_next()

{

    next[] = -;

    int j = -;

    int i = ;

    int str = strlen(b);

    while(i < str - )

    {

        if(j == - || b[i] == b[j])

        {

            next[++i] = ++j;

        }

        else

        {

            j = next[j];

        }

    }

}

5、给出一份完整代码:


#include<iostream>

#include<cstdio>

#include<cstring>

using namespace std;

char a[];

char b[];

int next[];

void get_next()

{

    next[] = -;

    int j = -;

    int i = ;

    int str = strlen(b);

    while(i < str - )

    {

        if(j == - || b[i] == b[j])

        {

            next[++i] = ++j;

        }

        else

        {

            j = next[j];

        }

    }

}

int index_KMP()

{

    int stra = strlen(a);

    int strb = strlen(b);

    int i = -,j = -;

    while(i < stra && j < strb)

    {

        if(j == - || a[i] == b[j])

        {

            i++;j++;

        }

        else

        {

            j = next[j];

        }

    }

    if(j >= strb)

    {//在a中找到了b字符串

        return ;

    }

    return ;

}

int main()

{

    while(scanf("%s%s",a,b)!=EOF)

    {

        get_next();

        if(index_KMP())

        {

            printf("YES\n");

        }

        else

        {

            printf("NO\n");

        }

    }

    return ;

}

运行结果:

KMP(字符串匹配)的更多相关文章

  1. {Reship}{KMP字符串匹配}

    关于KMP字符串匹配的介绍和归纳,作者的思路非常清晰,推荐看一下 http://blog.csdn.net/v_july_v/article/details/7041827

  2. 洛谷P3375 - 【模板】KMP字符串匹配

    原题链接 Description 模板题啦~ Code //[模板]KMP字符串匹配 #include <cstdio> #include <cstring> int cons ...

  3. Luogu 3375 【模板】KMP字符串匹配(KMP算法)

    Luogu 3375 [模板]KMP字符串匹配(KMP算法) Description 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来 ...

  4. 洛谷P3375 [模板]KMP字符串匹配

    To 洛谷.3375 KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.如果 ...

  5. P3375 【模板】KMP字符串匹配

    P3375 [模板]KMP字符串匹配 https://www.luogu.org/problemnew/show/P3375 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在 ...

  6. 洛谷—— P3375 【模板】KMP字符串匹配

    P3375 [模板]KMP字符串匹配 题目描述 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next. (如 ...

  7. P3375 模板 KMP字符串匹配

    P3375 [模板]KMP字符串匹配 来一道模板题,直接上代码. #include <bits/stdc++.h> using namespace std; typedef long lo ...

  8. KMP字符串匹配 模板 洛谷 P3375

    KMP字符串匹配 模板 洛谷 P3375 题意 如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置. 为了减少骗分的情况,接下来还要输出子串的前缀数组next.(如果 ...

  9. KMP字符串匹配学习

    KMP字符串匹配学习 牛逼啊 SYC大佬的博客

随机推荐

  1. Django admin site(三)InlineModelAdmin

    InlineModelAdmin class InlineModelAdminclass TabularInlineclass StackedInline 举例,有两个Model: from djan ...

  2. laravel速记(笔记)

    命令行: php artisan controller:make UserController This will generate the controller at /app/controller ...

  3. Entity Framework学习 - 2.增删改查

    1.增加数据 PirateBayEntities db = new PirateBayEntities(); T_Tests test = new T_Tests(); test.Name = &qu ...

  4. Android权限安全(6)四大组件自定义权限示例

    Activity service ContentProvider BroadcastReceiver

  5. C# App.config 详解

      读语句: String str = ConfigurationManager.AppSettings["DemoKey"]; 写语句: Configuration cfa = ...

  6. chrome浏览器无法设置打开特定网页

    最近chrome浏览器更新后,发现以前设置的启动浏览器“重上次停下的地方继续”功能消失了. 当我点击设置网页时,会出现如上提示. 后来有同事给了如下一个连接,里面说到这个是公司的超级管理员搞的,他定义 ...

  7. 【Todo】【转载】ES6的学习记录

    粗略看了一遍React的内容,然后看了 ES6 的入门文章: http://es6.ruanyifeng.com/#docs/intro 通过这个链接可以查看浏览器对 ES6 的支持程度: http: ...

  8. uva 1642 Magical GCD

    很经典的题目,愣是没做出来.. 题意:给出一个序列,求一子序列,满足其GCD(子序列)* length(子序列)最大. 题解: 类似单调队列的思想,每次将前面所得的最大公约数与当前数进行GCD,若GC ...

  9. 4197: [Noi2015]寿司晚宴

    状压dp. 500分解质因数的话,除了最大的质因数只需要8个质数,用二进制x储存,最大的质因数用y来储存(若没有比那8个质数大的质因数就使y=1) 用f[i][j]表示第一个人方案为i,第二个人方案为 ...

  10. LeetCode Triangle 三角形(最短路)

    题意:给一个用序列堆成的三角形,第n层的元素个数为n,从顶往下,每个元素可以选择与自己最近的两个下层元素往下走,类似一棵二叉树,求最短路. [], [,4], [6,,7], [4,,8,3] 注意: ...