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. 24-语言入门-24-cigarettes

    题目地址: http://acm.nyist.edu.cn/JudgeOnline/problem.php?pid=94    描述Tom has many cigarettes. We hypoth ...

  2. Support Library官方教程(2)各支援包的特性详介(含表)*

    快速阅读 包名  作用  位置 是否有资源 v4 提供了最多的api <sdk>/extras/android/support/v4/ y Multidex 把DEX文件生成apk < ...

  3. php整理(一):变量和字符串

    PHP中的变量: 1. 定义:$符号来定义变量 2. 说明: (1)PHP弱语言,定义变量的时候不用声明类型,但是并不代表PHP没有数据类型 (2)变量名是区分大小写的,只能是数字,字母或者下划线 ( ...

  4. ExtJs自学教程(1):一切从API开始

    题 记 该系列文章不侧重全方位的去介绍ExtJs的使用,只是侧重于解决ExtJs问题的思考方法.写的人不用长篇大论,学的人则能够自立更生.l  学习的人只要有一些CSS的javascript的基础知识 ...

  5. SqlServer中获取数据库中每个表的行数

    CREATE TABLE #RowCounts(NumberOfRows BIGINT,TableName VARCHAR(128)) EXEC sp_MSForEachTable 'INSERT I ...

  6. Apache httpd + tomcat 简单集群

    集群其实很简单,我们就来说一下httpd+tomcat集群都要注意哪些部分: 首先使用的东西有 apache-tomcat-8.0.32      下载地址: http://tomcat.apache ...

  7. How can I add a new user as sudoer using the command line?

    Two ways to use sudo command for a standard user account: First, If you want to use sudo command for ...

  8. 一个简单的iBatis入门例子

    一个简单的iBatis入门例子,用ORACLE和Java测试 目录结构: 1.导入iBatis和oracle驱动. 2.创建类Person.java package com.ibeats;import ...

  9. 【笨嘴拙舌WINDOWS】编码历史

    在介绍历史之前,有必要将一个经常使用的词语"标准"解释一下: " 标准是"为了在一定的范围内获得最佳秩序,经协商一致制定并由公认机构批准,共同使用的和重复使用的 ...

  10. HNOI2008越狱(快速幂)

    快速幂水过,贴一下模版. ; var x,y,n,m:int64; function power(num,times:int64):int64; var temp:int64; begin then ...