KMP算法利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度O(m+n)。

Next()函数的详解

  • 把将要进行next计算的字符串S分成 k ,j 前后两串,k代表前串开头所在的序号,j代表后串开头所在的序号,起始的时候j=1,k=0。
  • 我们比较一下前串 后串是否相等,要怎么比较呢,肯定是比较S[j]==S[k],如果相等,那么next[j+1]=k+1,然后j++,k++。关键就是理解这个next[j+1]=k+1(为什么k+1?):简单说就是S串中的第j+1个字符的next函数值由他前面的字符与前串相等的个数来决定,就是说串中的第j+1个字符的next函数值,是由他前面的字符串决定的。
  • 当S[j]!=S[k],即不相等的时侯,那么j不动,k返回到开头(因该是next[k]位置,便于理解先假设是返回k=0处),即从头比较S[0]与S[j],S[1]与S[j+1]。

  例如:第 j+1 个字符的next函数值next[j+1]等于3,意味着它的前三个字符串,S[j-2]S[j-1]S[j] =S[0]S[1]S[2]。

例一:模式串:abcaabcba

下标

0

1

2

3

4

5

6

7

8

模式串

a

b

c

a

a

b

c

b

a

next值

-1

0

0

0

1

1

2

3

0

1.第一个字符的next值令为-1。令第二个字符b的next值为0。初始k=0,j=1。开始比较S[k] 和S[j]。

2.比较S[0] !=S[1],所以j++,k不变,next[j=2]=k=0。

3.比较S[0] !=S[2],所以j++,k不变,next[j=3]=k=0。

4.比较S[0]==S[3],所以j++,k++,next[j=4]=k=1。

5.k=1了,所以比较S[1] !=S[4],k返回到next[k]位置,即k=next[1]=0,然后比较S[k=0] == S[4],所以 j++,k++,next[j=5]=k=1。

6.比较S[1]==S[5],所以j++,k++,next[6]=k=2。

7.比较S[2]==S[6],所以j++,k++,next[7]=k=3。

8.比较S[3] !=S[7],所以k返回到next[k=3]位置,即k=next[3]=0,然后比较S[k=0] !=S[7],所以j++,k=0不变,next[8]=k=0。

在例一中,每次不相等时返回的都是k=next[k]=0,都是返回到了开头,下面一个不是返回到开头0的情况:

例二:模式串:aabcaaabaac

下标

0

1

2

3

4

5

6

7

8

9

10

模式串

a

a

b

c

a

a

a

b

a

a

c

next值

-1

0

1

0

0

1

2

2

3

1

2

从 j=5,k=1的时候开始

5.比较S[1]==S[5],所以j++,k++,next[j=6]=k=2。

6.比较S[2] !=S[6],所以k返回到next[k=2]位置,即k=next[2]=1,然后比较S[k=1]==S[6],所以 j++,k++,next[7]=k=2。

……

因此,发现K的退回是退回到next[k]的位置,即S[j]!=S[k]时,k=next[k]。

KMP的算法思想

和BF算法相比,KMP算法主要是在模式串上下功夫,通过先求得模式串对应的next[ ]数组,当两个字符串中字符匹配失败时候将模式串的下标回溯到next[ ]中存储的下标位置,而BF算法是直接回溯到模式串的0下标,即开始第一个字符。所以KMP算法的时间复杂度要比BF算法好。

KMP算法代码

 #include<stdio.h>
#include<string.h> char* s = "aabcaaabaac";
char* t = "aac"; int next[]; //定义next数组 void getNext(char *s, int next[])
{
int k=-; / /k代表前串起始位置
int j=; //后串起始位置,一直增加
next[] = -; //令第一个字符的next值为-1 while(j < strlen(s) - ) //当后串小于最大下标-1
{
if(k == - || s[j] == s[k]) //匹配的情况下,即s[j]==s[k],next[j+1]=k+1;
{
++j;
++k;
next[j] = k;
}
else //若不匹配,即p[j]!=p[k],k=next[k]
k = next[k];
}
} int KMP(char* s, char* t)
{
int i = ; //i从s串开始
int j = ; //j从t串开始
int sLength = strlen(s); //s串的长度
int tLength = strlen(t); //t串的长度
while((i < sLength) && (j < tLength)) //当下标i和j都不越界时
{
if(j == - || s[i] == t[j]) //当模式串t中第一个字符与目标串s中某个字符匹配失败时,i应该移动到目标串s的下一个目标,再和模式串t的第一个字符进行比较,或者s的第i个字符和t的第j个字符相等,则将i++和j++
{
i++;
j++;
}
else
{
//i=i-j+1;j=0; //这是普通的BF算法,将模式串的下标从0开始
j = next[j]; //KMP算法是将模式串的j下标从next[j]开始
}
}
if(j >= tLength)
return i - tLength;
else
return ;
} int main()
{
getNext(s, next);
printf("%d", + KMP(s, t));
return ;
}

KMP字符串匹配算法详解的更多相关文章

  1. KMP字符串模式匹配详解(zz)

    刚看到位兄弟也贴了份KMP算法说明,但本人觉得说的不是很详细,当初我在看这个算法的时候也看的头晕昏昏的,我贴的这份也是网上找的.且听详细分解: KMP字符串模式匹配详解 来自CSDN     A_B_ ...

  2. KMP字符串模式匹配详解

    KMP字符串模式匹配详解 http://www.cppblog.com/oosky/archive/2006/07/06/9486.html

  3. KMP字符串模式匹配详解(转)

    来自CSDN     A_B_C_ABC 网友 KMP字符串模式匹配通俗点说就是一种在一个字符串中定位另一个串的高效算法.简单匹配算法的时间复杂度为O(m*n);KMP匹配算法.可以证明它的时间复杂度 ...

  4. KMP字符串匹配算法翔解❤

    看了Angel_Kitty学姐的博客,我豁然开朗,写下此文: 那么首先我们知道,kmp算法是一种字符串匹配算法,那么我们来看一个例子. 比方说,现在我有两段像这样子的字符串: 分别是T和P,很明显,P ...

  5. Java 字符串格式化详解

    Java 字符串格式化详解 版权声明:本文为博主原创文章,未经博主允许不得转载. 微博:厉圣杰 文中如有纰漏,欢迎大家留言指出. 在 Java 的 String 类中,可以使用 format() 方法 ...

  6. jquery $.trim()去除字符串空格详解

    jquery $.trim()去除字符串空格详解 语法 jQuery.trim()函数用于去除字符串两端的空白字符. 作用 该函数可以去除字符串开始和末尾两端的空白字符(直到遇到第一个非空白字符串为止 ...

  7. Python 字符串方法详解

    Python 字符串方法详解 本文最初发表于赖勇浩(恋花蝶)的博客(http://blog.csdn.net/lanphaday),如蒙转载,敬请保留全文完整,切勿去除本声明和作者信息.        ...

  8. shell字符串操作详解

    shell字符串操作详解的相关资料. 1.shell变量声明的判断  表达式 含义 ${var} 变量var的值, 与$var相同 ${var-DEFAULT} 如果var没有被声明, 那么就以$DE ...

  9. C#的String.Split 分割字符串用法详解的代码

    代码期间,把代码过程经常用的内容做个珍藏,下边代码是关于C#的String.Split 分割字符串用法详解的代码,应该对码农们有些用途. 1) public string[] Split(params ...

随机推荐

  1. Dubbo的SPI机制与JDK机制的不同及原理分析

    从今天开始,将会逐步介绍关于DUbbo的有关知识.首先先简单介绍一下DUbbo的整体概述. 概述 Dubbo是SOA(面向服务架构)服务治理方案的核心框架.用于分布式调用,其重点在于分布式的治理. 简 ...

  2. P1002 过河卒【dp】

    P1002 过河卒 题目描述 棋盘上AAA点有一个过河卒,需要走到目标BBB点.卒行走的规则:可以向下.或者向右.同时在棋盘上CCC点有一个对方的马,该马所在的点和所有跳跃一步可达的点称为对方马的控制 ...

  3. 跨站脚本(XSS)

    1.1 XSS定义 XSS,即为(Cross Site Scripting),中文名为跨站脚本,是发生在目标用户的浏览器层面上的,当渲染DOM树的过程发生了不在预期内执行的JS代码时,就发生了XSS攻 ...

  4. liunx下安装Docker

    1.安装并启动docker 1.检查内核版本,必须是3.10及以上uname -r2.安装docker yum install docker命令安装(需要联网) [root@localhost ~]# ...

  5. Django学习笔记3

    From the last two parts, we know, by using the HttpResponse we can return text to the web page, and ...

  6. scrapy爬虫保存数据

    1.数据保存为TXT 打开Pipeline.py import codecs import os import json import pymysql class CoolscrapyPipeline ...

  7. linux 中对 mysql 数据表的基本命令

    显示数据表的结构 describe 表名; 建表 use 库名: create table 表名(字段设定列表): 将表中记录清空 delete from 表名; 删表 drop table 表名:

  8. (转)hashmap hashtable 的区别 Hash table 内部的数据结构

    转自:http://www.cnblogs.com/carbs/archive/2012/07/04/2576995.html Hashtable 和 HashMap 做为 Map 的基本特性 两者都 ...

  9. POJ3122 Pie(二分)

    题目链接:http://poj.org/problem?id=3122 题意:一堆人分蛋糕,每人蛋糕大小一样,求最大能分多少,蛋糕必须是整块整块的,不能两块拼一起.然后注意输入F个人最后要分F+1份. ...

  10. vue里不同数据的循环,其中的数组对象

    用产品的属性数据说明 页面里显示效果为:要把产品的属性显示到页面上,产品属性为后台自主上传产品的属性,产品的属性不同,所以需要把属性和属性值显示到页面上 产品属性数据为: properties: &q ...