扩展的KMP算法,可以在Ο(n + m)的时间复杂度内计算出模板串与文本串的每一个后缀的最长公共前缀,即LCP(T[i:n],P)。

KMP算法所解决的单模板字符串匹配问题,求得的匹配点是LCP = m的位置,属于该算法的子问题。扩展的KMP算法可以获得更多信息。

定义:文本串长度为n,模板串长度为m

   next[i]:模板串P[i:m]和P的最长公共前缀

   extend[i]:文本串T[i:n]和P的最长公共前缀(待求)

   习惯上使用左闭右开区间,下标从0开始,字符串采用Python的表示法

算法思想:

最大程度利用已匹配的串的信息

算法思路:

假设我们已知了next数组,且当前已知T[p:mx]与P的前缀是匹配的。

设mx表示文本串当前已匹配到的最末位置的下一位置(代比较的位置),p表示与之匹配的模板串与文本串的对齐位置,i表示当前要计算extend值的位置

比较i+next[i-p]与mx的大小关系,分为两种情况

  • if (i + next[i - p] < mx)

如图,我们知道p到mx这一段的文本串与模板串是相等的,根据模板串自身的next数组可以知道文本串的extend值至少是next[i - p],又next数组的定义是“最长”,即确定了下一位不相等。所以extend[i] = next[i - p]

  • else

当i + next[i - p] >= mx时,模板串p-i位置的最长公共前缀超出了已知的文本串的范围。我们最大程度地利用已知信息,i位置的extend长度就应当从mx-i开始扩展,接下来比较T[mx]和P[mx - i](标✦的位置),更新答案和mx、p的值。

匹配算法完毕。接下来我们要考虑模板串的next数组的求法

注意到,   next是模板串与模板串的LCP

      extend是文本串与模板串的LCP

所以——next的生成其实就是自己对自己套用该算法。我们甚至不需要改变代码,只需令T=P,带入函数即可。

实现细节

#1由于模板串在匹配自身时在初始位置完全相同,要避免mx在一开始就跳到末尾,所以要加个特判,当匹配自身时,要跳过第一位开始比较。

#2当i>=mx时要更新mx的值为i,重返暴力操作


模板题:洛谷P5410

AC代码:

void exKMP(const char* P, int* nxt, const char* T, int* ext)  P为模板串,nxt是模板串的next数组,T为文本串,ext储存待求的extend值;当ext==nxt时判断为匹配自身,启动特判

 #include <iostream>
#include <string>
#include <cstring>
#include <iterator>
using namespace std; const int maxn = 1e5 + ;
int nxtP[maxn], Lcp[maxn];
void exKMP(const char* P, int* nxt, const char* T, int* ext) {
int i, mx = , p = , n = strlen(T), m = strlen(P); //mx: Position where doesn't fit.
if (nxt == ext) {
ext[] = n;
p = ; mx = ; i = ;
while (mx < n && mx - i < m && T[mx] == P[mx - i]) mx++;
} else i = ; for (; i < n; ++i)
if (nxt[i - p] + i < mx) ext[i] = nxt[i - p];
else {
if (i >= mx) mx = i; //i >= mx
while (mx < n && mx - i < m && T[mx] == P[mx - i]) mx++;
ext[i] = mx - i;
p = i;
}
return;
}
signed main() {
string T, P;
cin>>T>>P;
exKMP(P.data(), nxtP, P.data(), nxtP);
exKMP(P.data(), nxtP, T.data(), Lcp);
copy(nxtP, nxtP + P.length(), ostream_iterator <int> (cout, " "));
cout<<endl;
copy(Lcp, Lcp + T.length(), ostream_iterator <int> (cout, " "));
return ;
}

扩展的KMP算法图解的更多相关文章

  1. 字符串模式匹配之KMP算法图解与 next 数组原理和实现方案

    之前说到,朴素的匹配,每趟比较,都要回溯主串的指针,费事.则 KMP 就是对朴素匹配的一种改进.正好复习一下. KMP 算法其改进思想在于: 每当一趟匹配过程中出现字符比较不相等时,不需要回溯主串的 ...

  2. KMP算法图解

    字符串匹配是计算机的基本任务之一. 举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD" ...

  3. 扩展KMP算法

    一 问题定义 给定母串S和子串T,定义n为母串S的长度,m为子串T的长度,suffix[i]为第i个字符开始的母串S的后缀子串,extend[i]为suffix[i]与字串T的最长公共前缀长度.求出所 ...

  4. 扩展KMP算法小记

    参考来自<拓展kmp算法总结>:http://blog.csdn.net/dyx404514/article/details/41831947 扩展KMP解决的问题: 定义母串S和子串T, ...

  5. KMP算法模板&&扩展

    很不错的学习链接:https://blog.csdn.net/v_july_v/article/details/7041827 具体思路就看上面的链接就行了,这里只放几个常用的模板 问题描述: 给出字 ...

  6. 神奇的字符串匹配:扩展KMP算法

    引言 一个算是冷门的算法(在竞赛上),不过其算法思想值得深究. 前置知识 kmp的算法思想,具体可以参考 → Click here trie树(字典树). 正文 问题定义:给定两个字符串 S 和 T( ...

  7. 图解算法——KMP算法

    KMP算法 解决的是包,含问题. Str1中是否包含str2,如果包含,则返回子串开始位置.否则返回-1. 示例1: Str1:abcd123def Str2:123d 暴力法: 从str1的第一个字 ...

  8. hdu 4300 kmp算法扩展

    Clairewd’s message Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Other ...

  9. 初探KMP算法

            数据结构上老师也没讲这个,平常ACM比赛时我也没怎么理解,只是背会了代码--前天在博客园上看见了一篇介绍KMP的,不经意间就勾起了我的回忆,写下来吧,记得更牢. 一.理论准备      ...

随机推荐

  1. 数据结构与算法学习(二)——Master公式及其应用

    本篇文章涉及公式,由于博客园没有很好的支持,建议移步我的CSDN博客和简书进行阅读. 1. Master公式是什么? 我们在解决算法问题时,经常会用到递归.递归在较难理解的同时,其算法的复杂度也不是很 ...

  2. 【VS开发】Wix 安装教程

    original link :  http://www.cnblogs.com/stoneniqiu/p/3355086.html 因为项目需要,最近在研究Wix打包部署,园子里也有一些关于wix ...

  3. 批量添加删除Windows server DNS服务 恶意域名 * A记录 指向 127.0.0.1(2019年6月5日更新)

    下载链接:https://pan.baidu.com/s/1OUHyvnIfXYF0PdiT-VRyHw  密码:7gjj 注意!本解决方案在本地的Windows server服务器上把恶意域名指向1 ...

  4. [转帖]详解shell脚本括号区别--$()、$「 」、$「 」 、$(()) 、「 」 、「[ 」]

    详解shell脚本括号区别--$().$「 」.$「 」 .$(()) .「 」 .「[ 」] 原创 波波说运维 2019-07-31 00:01:00 https://www.toutiao.com ...

  5. SQLServer 查询view中是否包含某个关键字

    在数据库view的创建中,会遇到一些跨数据库的view脚本,但是在将view更新到production的时候可能忘记更改database name,导致出现一些问题. 以下脚本可以检查出包含某个关键字 ...

  6. 还是a+b

    题目描述: 给定 2 个正整数 a, b,a 和 b 最多可能有 40 位,求出 a + b 的和.输入描述: 两个正整数 a, b,a 和 b 最多可能有 40 位.一行表示一个数.输出描述: a ...

  7. 剑指offer60:把二叉树打印成多行。上到下按层打印二叉树。

    1 题目描述 从上到下按层打印二叉树,同一层结点从左至右输出.每一层输出一行. 2 思路和方法 vector变量存储每一层的元素vector<vector<int> > ans ...

  8. ubuntu内lnmp相关操作命令

    LNMP状态管理命令: **LNMP状态管理:** sudo lnmp {start|stop|reload|restart|kill|status} **Nginx状态管理:**sudo /etc/ ...

  9. Python基础 第6章 抽象

    1. 引言及抽象和结构 生成斐波那契数列的代码如下: fibs = [0, 1] num = int(input('How many num you want:')) for x in range(n ...

  10. Django ORM 高性能查询优化

    一.QuerySet 可切片 使用Python 的切片语法来限制查询集记录的数目 .它等同于SQL 的LIMIT 和OFFSET 子句. >>> Entry.objects.all( ...