KMP 算法(2):其细微之处

  • 2017 年 05 月 13 日
  • 技术

系列文章目录

KMP 算法(1):如何理解 KMP
KMP 算法(2):其细微之处

本篇来谈一谈 KMP 的一些细微之处,直接进入主题。

一:起始下标之 “争”:0 和 1展开目录

/* P 为模式串,下标从 0 开始 */
void GetNext(string P, int next[])
{
int p_len = P.size();
int i = 0; // P 的下标
int j = -1; // 相同真前后缀的长度
next[0] = -1; while (i < p_len)
{
if (j == -1 || P[i] == P[j])
{
i++;
j++;
next[i] = j;
}
else
j = next[j];
}
} /* 在 S 中找到 P 第一次出现的位置 */
int KMP(string S, string P, int next[])
{
GetNext(P, next); int i = 0; // S 的下标
int j = 0; // P 的下标
int s_len = S.size();
int p_len = P.size(); while (i < s_len && j < p_len)
{
if (j == -1 || S[i] == P[j]) // P 的第一个字符不匹配或 S[i] == P[j]
{
i++;
j++;
}
else
j = next[j]; // 当前字符匹配失败,进行跳转
} if (j == p_len) // 匹配成功
return i - j; return -1;
}

上述代码的起始下标都是从 0 开始的,但每个人对数组起始位置的编码习惯不同,分为两类:0 和 1。对于上面的代码,起始位置如果改为 1 的话又是怎样呢?

 

但它们的区别并不止如此。我们知道,KMP 算法的 next[i] 表示最长的相同真前后缀,但这对起始位置为 1 的 next[i] 却不再适用。

i 0 1 2 3 4 5 6

7

模式串 A B C D A B D

'\0'

next[i] -1 0 0 0 0 1 2

0

i 1 2 3 4 5 6 7

8

模式串 A B C D A B D

'\0'

next[i] 0 1 1 1 1 2 3

1

上面两个表格表展示的是:相同模式串下不同起始位置的 next 值对比。

相比之下,起始位置为 1 的 next 值比起始位置为 0 的 next 值多了 1。多 1,不是巧合,而是必然。这很容易证明。

在 GetNext() 中,j 从 0 开始(起始位置为 1),在走了相等步后停下依次赋值给 next[i],因此相较于起始位置为 0 的 next 总是多 1。这又引起了我们的思考,多了 1 后在模式匹配中,next 还会正确的实现跳转么?当然会了,next 多 1,同时模式串的起始位置也多了 1,这就好比数学中,从 a=b 转化为 a+1=b+1,形式不同但完全等价。

二:next[i] 里最不起眼处的妙用展开目录

先来看一个问题,在主串 S 中找到模式串 P 所有可以完全匹配的位置。

很简单,典型的 KMP 模式匹配。

假设起始位置都是从 0 开始,对于上图,若已找到主串的第一个完全匹配位置即 0--4,那么请问接下来模式串如何移动?

不知道各位读者有没有注意过模式串最后末尾处的 next 值代表什么?(末尾即为字符串的结尾标志:'\0')

它代表整个模式串的最长相同真前后缀。

利用这个 next 值,我们直接可以实现跳转,更快地找到下一个匹配点。

KMP(2)的更多相关文章

  1. KMP算法求解

    // KMP.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include<iostream> using namespac ...

  2. 简单有效的kmp算法

    以前看过kmp算法,当时接触后总感觉好深奥啊,抱着数据结构的数啃了一中午,最终才大致看懂,后来提起kmp也只剩下“奥,它是做模式匹配的”这点干货.最近有空,翻出来算法导论看看,原来就是这么简单(先不说 ...

  3. KMP算法

    KMP算法是字符串模式匹配当中最经典的算法,原来大二学数据结构的有讲,但是当时只是记住了原理,但不知道代码实现,今天终于是完成了KMP的代码实现.原理KMP的原理其实很简单,给定一个字符串和一个模式串 ...

  4. 萌新笔记——用KMP算法与Trie字典树实现屏蔽敏感词(UTF-8编码)

    前几天写好了字典,又刚好重温了KMP算法,恰逢遇到朋友吐槽最近被和谐的词越来越多了,于是突发奇想,想要自己实现一下敏感词屏蔽. 基本敏感词的屏蔽说起来很简单,只要把字符串中的敏感词替换成"* ...

  5. [KMP]【学习笔记】

    Oulipo Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 36916   Accepted: 14904 Descript ...

  6. KMP算法实现

    链接:http://blog.csdn.net/joylnwang/article/details/6778316 KMP算法是一种很经典的字符串匹配算法,链接中的讲解已经是很明确得了,自己按照其讲解 ...

  7. KMP专题

    1.[HDU 3336]Count the string(KMP+dp) 题意:求给定字符串含前缀的数量,如输入字符串abab,前缀是a.ab.aba.abab,在原字符串中出现的次数分别是2.2.1 ...

  8. KMP学习之旅

    说起kmp就要从字符串的匹配说起,下面我们谈谈字符串的匹配 给定一个原字符串:bababababababababb,再给定一个模式串:bababb,求模式串是否在源字符串中出现 最简单的方法就是遍历源 ...

  9. KMP模板

    参考:http://www.cnblogs.com/c-cloud/p/3224788.html #include<stdio.h> #include<string.h> vo ...

  10. 【字符串匹配】KMP算法和next数组的c/c++实现

    KMP算法基本思想有许多博客都写到了,写得也十分形象,不懂得可以参考下面的传送门,我就不解释基本思想了.本文主要给出KMP算法及next数组的计算方法(主要是很多网上的代码本人(相信应该是许多人吧)看 ...

随机推荐

  1. Solr学习总结(六)solr的函数查询Function Queries

    摘要: 函数查询允许你使用一个或多个数字字段的真实值生成一个相关性分数,函数查询在standard,DisMax,eDisMax下都能使用. 查询函数可以是常量,字段或者其他函数的组合.使用函数可以影 ...

  2. uva-11205-枚举子集

    题意: 至少用多少列来表示输入中的二进制数,并且表示的数里面没有重复,最多P列,N个二进制数 所以......表示的最大二进制数是2^P,那么在2^P方内的数二进制最大值是P个1,最小是0,所以,枚举 ...

  3. 最小生成树-kruskal

    kruskal算法,没有进行算法复杂度分析 判断俩个结点是否在同一个树上使用了dfs,比较low的写法 输入数据 //第一行,结点数,结点数,边数 9 9 14a b 4b c 8c d 7a h 8 ...

  4. python第一个爬虫的例子抓取数据到mysql,实测有数据

    python3.5 先安装库或者扩展 1 requests第三方扩展库 pip3 install requests 2 pymysql pip3 install pymysql 3 lxml pip3 ...

  5. 24. Swap Nodes in Pairs + 25. Reverse Nodes in k-Group

    ▶ 问题:单链表中的元素进行交换或轮换. ▶ 24. 每两个元素进行翻转.如 [1 → 2 → 3 → 4 → 5] 变换为 [2 → 1 → 4 → 3 → 5] ● 初版代码,4 ms class ...

  6. ajax 实现跨域

    ajax本身是不可以跨域的,通过产生一个script标签来实现跨域.因为script标签的src属性是没有跨域的限制的. 其实设置了dataType: 'jsonp'后,$.ajax方法就和ajax ...

  7. 批量得到/修改word超链接

    Alt+F9或者勾选下面 此时的超链接地址全部转换为文本形式进行显示; 然后可以用全局替换搜索来处理

  8. Activity服务类-6 ManagementService服务类

    一共含有17个方法 // 获取包含了Activiti数据库模式的{表名.行计数}项的映射.Map<String, Long> getTableCount();//获取诸如任务.执行之类的A ...

  9. Mysql canal 监控数据变化

    https://www.jianshu.com/p/6299048fad66 阿里巴巴github地址 https://github.com/alibaba/canal/wiki/QuickStart

  10. zookeeper介绍以及安装配置

    Zookeeper启动时默认将Zookeeper.out输出到当前目录,不友好.改变位置有两种方法: 1:在当前用户下~/.bash_profile或在/etc/profile,添加ZOO_LOG_D ...