浅谈扩展KMP算法

IATF16949核心职位全解析 TM / Top MgmtMR / QMRProcess OwnerQMQAQCSQECQEPQEPETEMEIEPM / PJMFMEA ModeratorMSA CoordinatorSPC CoordinatorCM / CCB内审员CP / CPK 阅读详情

前言

首先,kmp算法大家都知道,但是听到扩展kmp的时候,会想到底是干什么的?
那么扩展kmp算法是用来求解下面问题的:

给定母串S,和子串T。
定义 n=|S| , m=|T| , extend[i]=S[i..n] 与T的最长公共前缀长度。请在线性的时间复杂度内,求出所有的 extend[1..n] 。

我们其实可以知道,如果有某个位置i满足 extend[i]=m ,那么T就肯定在S中出现过,并且进一步知道出现首位置是i——而这正是经典的KMP问题。
因此可见“扩展的KMP问题”是对经典KMP问题的一个扩充和加难。

算法描述

在解上面这个问题前我们要先解决一个类似的问题:求字符串s的所有后缀和s本身的最长公共前缀;
我们用next[]数组保存这些值;
现在我们假设要求 next[x] ,并且 next[i]0<i<x 的值都已经求出;
我们设 p=k+next[k]−1 , k是使p最大的i( 0<i<x );如图:

这里写图片描述

现在整理一下所解问题:
已知: s[k..p]==s[0..next[k]−1] ,求 s[x..n−1] 与 s[0..n−1] 的最长公共前缀;
由 s[k..p]==s[0..next[k]−1] 得:
s[x..p]==s[x−k..next[k]−1] ———1//这个是显然的
并设 L1=p−x+1 ;
因为 x−k 肯定是小于x的所以 L2=next[x−k] 是已知的,得:
s[0..L2−1]==s[x−k..x−k+L2−1] ; ——–2
通过等式1,2可以推出 s[0..k1]==s[x..k2]
当 L1≤L2 如下图
这里写图片描述
此时表示 s[0..L1−1]==s[x..x+L1−1] 但不能确定蓝色部分是否相等,所以需要继续比下去

当 L1>L2 如下图:
这里写图片描述

此时表示 s[0..L2−1]==s[x..x+L2−1] 而且因为 L2=next[x−k] 使得 s[L2]!=s[x+L2]
所以 next[x]=L2 ;

回到原来的问题

假设此时已经求出 next[] ,我们用 extend[] 保存字符串S的所有后缀和字符串T的最长公共前缀的值
我们重复上面的过程:
现在我们假设要求 extend[x] ,并且 extend[i]0<i<x 的值都已经求出;
我们设 p=k+extend[k]−1 , k是使p最大的 i ( 0<i<x );如图:
这里写图片描述

现在整理一下问题:

已知: s[k..p]==T[0..extend[k]−1] ,求 s[x..n−1] 与 T[0..m−1] 的最长公共前缀;
由 s[k..p]==T[0..extend[k]−1] 得:
s[x..p]==T[x−k..extend[k]−1] ———1//同样这个是显然的
并设 L1=p−x+1 ;
因为 x−k 肯定是小于x的所以 L2=next[x−k] 是已知的,得:
T[0..L2−1]==T[x−k..x−k+L2−1]; ——–2
通过等式1,2可以推出 T[0..k1]==s[x..k2]
当 L1≤L2 如下图
这里写图片描述
表示 T[0..L1−1]==s[x..x+L1−1] 但不能确定蓝色部分是否相等,所以需要继续比下去

当 L1>L2 如下图:
这里写图片描述
表示 T[0..L2−1]==s[x..x+L2−1] 而且因为 L2=extend[x−k] 使得 T[L2]!=s[x+L2]
所以 extend[x]=L2 ;

如果你仔细阅读的话可能会发现并没有说 next[] 怎么求,我们发现计算next实际上以T为母串、T为子串的一个特殊“扩展的KMP”。具体可以参考标准KMP的求法就行了。

复杂度分析

容易看出,在计算的过程中,凡是访问过的点,都不需要重新访问了。一旦比较,都是比较以前从不曾探访过的点开始。因此总的时间复杂度是 O(n+m) ,是线性的。

应用例题

这里有一道例题可以练手:HDU4333

题意:给一个数字,每一次把它的最后一位拿到最前面,一直那样下去,分别求形成的数字小于,等于和大于原来数的个数。
例如:134可以形成134,341,413三个数,所以分别是1,1,1。
数据范围:50组以内数据,数字大小在 10100000 以内。

由于长度为len的字符串形成题目要求的串的个数为len,那么我们可以把原来的两个串T连接起来形成字符串S,然后找S的每个后缀的前len个元素即可。
这里主要是如何比较的问题,对于字符串的比较,我们可以先求出他们的最长公共前缀长度,然后只需要比较一次就可以知道结果了。那么最长公共前缀怎么求,由于这里是一个串T与另一个串S,来求S的所有后缀与T的最长公共前缀长度,所以用扩展KMP。如果 extend[i]≥len ,就说明与原来的相等了,否则如果 S[i+extend[i]]<T[extend[i]] 就说明小于,否则就是大于。

另外还推荐一道题目POJ2185。

代码

代码是上面的例题的代码,同时中间的函数也可以当成模板来使用。

#include <cstdio>
#include <cstring>
#include <algorithm>

const int size = 500000+10;
int next[size],nextval[size],extend[size];
char s[size],t[size];

void Getnext(char *T) {
    int a=0,Tlen=strlen(T);
    next[0]=Tlen;
    while(a<Tlen-1&&T[a]==T[a+1]) a++;
    next[1]=a;a=1;
    for(int k=2;k<Tlen;k++) {
        int p=a+next[a]-1,L=next[k-a];
        if((k-1)+L>=p) {
            int j=(p-k+1)>0?p-k+1:0;
            while(k+j<Tlen&&T[k+j]==T[j]) j++;
            next[k]=j;a=k;
        }
        else next[k]=L;
    }
}

void Getextend(char *s,char *t) {
    int a=0;Getnext(t);
    int Slen=strlen(s),Tlen=strlen(t);
    int Minlen=std::min(Slen,Tlen);
    while(a<Minlen&&s[a]==t[a]) a++;
    extend[0]=a;a=0;
    for(int k=1;k<Slen;k++) {
        int p=a+extend[a]-1,L=next[k-a];
        if((k-1)+L>=p) {
            int j=(p-k+1)>0?p-k+1:0;
            while(k+j<Slen&&j<Tlen&&s[k+j]==t[j]) j++;
            extend[k]=j;a=k;
        }
        else extend[k]=L;
    }
}

void Nextval(char *t) {
    int i=0,j=-1;nextval[0]=-1;
    int Tlen=strlen(t);
    while(i<Tlen) {
        if(j==-1||t[i]==t[j]) {
            i++;j++;if(t[i]!=t[j]) nextval[i]=j;
            else nextval[i]=nextval[j];
        }
        else j=nextval[j];
    }
}

int Slen,Tlen;

int main()
{
    int Slen,Tlen,T=1,tt=1;
    scanf("%d",&T);
    while(T--) {
        scanf("%s",s);strcpy(t,s);
        strcat(s,t);Getextend(s,t);
        Tlen=strlen(t);Slen=strlen(s);
        Nextval(t);
        int MOD=Tlen-nextval[Tlen],temp=1;
        if(Tlen%MOD==0) temp=Tlen/MOD;
        int ans1=0,ans2=0,ans3=0;
        for(int i=0;i<Tlen;i++) {
            if(extend[i]>=Tlen) ans2++;
            else if(s[i+extend[i]]<t[extend[i]]) ans1++;
            else ans3++;
        }
        printf("Case %d: %d %d %d\n",tt++,ans1/temp,ans2/temp,ans3/temp);
    }
    return 0;
}

最后

针对字符串处理的许多算法,我们考虑的时候能够尽量保证:已经访问过的点绝不再访问,充分利用已经得到的信息。,这也是扩展kmp算法的魅力之所在。

VCSA 上的 vmware-vpxd 服务失败,Web端提示503 服务不可用 (503 Service Unavailable) 昨晚VCSA碰到一个很诡异的问题: 使用 vSphere Web Client 连接到 vCenter Server Appliance时失败,提示: 503 服务不可用 (503 Service Unavailable) 无法连接端点 (Failed to connect to endpoint):[N7Vmacore4Http20NamedPipeServiceSpecE:0x00007f975808ee30] _serverNamespace = / action = Allow _pipeNam 阅读详情

相关推荐

在 dell precision 7920 tower CentOS 8 Stream 上安裝nvidia驱动程序、Anaconda

简单记录一下如何在实验室dell precision 7920 tower CentOS 8 Stream上安装nvidia显卡驱动。

chen9046的博客 995

为什么JDK String为什么不使用KMP算法?

环境:JDK1.8 在JDK1.8中我点开了String的indexOf(String str)发现并没有使用KMP算法。那么为什么JDK不使用KMP算法呢? 1)大部分比较是短字符串,普通算法的O(nm)已经够用,而KMP算法在较短字符串里是O(n+m)。KMP算法的常数因子会拖慢算法。 2) 因为是公共库函数,需要考虑各种情况的性...

\(°ω°)\ 1580

图解“交易·支付·清结算·账务”全局

这个过程大致是这样的,用户先到平台选择喜欢的“餐品”,然后“下单”,生成交易“账单”,用户选择支付方式进行“支付”,支付成功后平台要履行承诺把餐送到,“履约”完成以后平台就开始进行各方利益的“清分”,计算清楚应给谁多少钱,并“记账”,最后将款项“结算”给商家,这个过程如图7所示。交易系统请求订单系统创建订单,因为不清楚平台和商家之间的清结算协议,所以暂且认为所有优惠由平台提供给用户,后续平台再基于协议跟商家之间做优惠的分摊,将上述商品、优惠、计价等信息集成到一起,就得到了完成的订单信息了,如表4所示。

wjianwei666的专栏 1万+

简单的讲懂KMP算法(配图最细保姆级手把手教会!!)

KMP 算法(Knuth-Morris-Pratt 算法)是一种高效的字符串匹配算法,他比较BF算法复杂度更低但是也更难理解,它的算法非常精妙减少了BF算法(暴力算法,上一篇博客有讲解)的无用重复操作大大减少了循环次数,再加上限制条件使得它的效率更加高效,我有看到许多大神在讲KMP算法但是大部分都是理论性讲述,不易懂打退了许多学者的热情以及自信心,我将会保姆级和大家分析KMP算法的思想以及代码的实现!!!

weixin_63426509的博客 6275

ESP8266+ITR8307实战:如何用反射式光电管实现5cm远距离检测(附避坑指南)

本文详细介绍了如何利用ESP8266的ADC功能与ITR8307反射式光电管,通过调制解调、硬件电路优化及软件同步采样策略,实现5cm稳定远距离检测。文章提供了完整的硬件设计、代码实现与调优避坑指南,有效解决了环境光干扰与信号衰减难题,适用于智能车、自动化等需要可靠非接触检测的项目。

rgv234567的博客 264

PySide6 vs PyQt6:新手如何根据Python版本选择GUI库?附版本兼容性测试

本文针对Python GUI开发新手,详细对比了PySide6与PyQt6的核心差异,并提供了基于Python 3.8至3.12等不同版本的兼容性实测数据与选择建议。文章重点分析了版本选择策略,帮助开发者根据自身Python环境、项目需求(如与matplotlib集成)及许可证考量,做出最合适的决策,并附有安装验证与避坑指南。

weixin_29094539的博客 703

经典算法之浅析kmp算法

         KMP算法,也就是字符串匹配算法,是很多场合都会用到的算法,这个算法想要解决什么样的问题呢?举例来说,有一个字符串"BBC ABCDAB ABCDABCDABDE",我想知道,里面是否包含另一个字符串"ABCDABD"?          传统的求解,我想很多人都已经想到了,遍历源字符串的每一位嘛,依次和要匹配的字符串比较,code很easy,但效率较为低下,可以想到,时间复杂度...

可乐小浣熊 538

边缘AI硬件风向:从专用芯片到端侧大模型

边缘AI硬件正呈现五大发展趋势:专用AI加速芯片(如华为昇腾、谷歌EdgeTPU)凭借高能效比成为主流;端侧大模型催生支持Transformer架构的新硬件需求;存算一体技术突破内存墙限制;FPGA和可重构计算提供灵活性;异构集成与Chiplet技术实现模块化设计。这些发展需要配套软件工具链支持,未来边缘设备将演变成具备本地智能的"智能体",竞争焦点转向算力、能效、易用性和成本的多维平衡。

qq_37027335的博客 348

KMP算法缺陷

但是对于只由两个字母组成的字符串,KMP算法的效率是最差的,因为在构造next数组的过程中,可能会出现大量的重复计算。当然,这种情况下的比较次数可能不是最少的,但是从整体来看,KMP 算法是一种比较高效的字符串匹配算法。如果当前失配元素和 next 数组下标对应子串元素一样,确实会有一些重复的比较,但这样的情况出现的概率并不高,而且在实际情况中对算法效率的影响不大,因此不会影响 KMP 算法的正确性和实用性。在使用KMP算法的时候,有时会发生失配元素和next下标子串对应元素会相同,这种情况相当于–白做。

qq_35516011的博客 605

ur3手眼标定+realsenseL515

知乎 csdn

AI_future的博客 978

华为OD机试真题 新系统 2026-08-16 Python&JS【智能家居模式调度优化】

智能家居系统中有多个自动化联动模式,每个模式 modes[i]=[start_time,end_time,power],表示它在左闭右开区间 [start_time,end_time) 内持续消耗固定功率 power。

MISAYAONE的博客 85

hdu 3068(扩展KMP)

//http://bbs.dlut.edu.cn/bbstcon.php?board=Competition&gid=23474 一个奇妙的o(n)算法,明天看看~~ 看完结果总结如下:   算法大致过程是这样。先在每两个相邻字符中间插入一个分隔符,当然这个分隔符要在原串中没有出现过。一般可以用‘#’分隔。这样就非常巧妙的将奇数长度回文串与偶数长度回文串统一起来考虑了(见下面的一个例子

SprintfWater的专栏 999

大中型超市收银系统(可直接运行)

光步前台收银系统系统功能:商品销售、商品退货、挂单、收银员权限、会员销售、单品取消、整单取消、商品查询、脱机销售、脱机数据上传,基本资料下载,开钱箱、小票打印、收款结算,支持多币种付款方式(现金、储值卡、礼券、微信等),支持多种促销。运行环境:.net 4.0登陆信息用户名:1001 密码:123456内置商品信息,商品编码可输入00001000 - 00010000,测试效果相关功能键F5 结算 F9挂单 F11商品查询 F8退货 Insert单品取消 Del整单取消 F12开钱箱F2 会员 Ctrl+Z退出系统 Home 锁屏 相关源码待公开

浅谈Manacher算法与扩展KMP之间的联系

首先,在谈到Manacher算法之前,我们先来看一个小问题:给定一个字符串S,求该字符串的最长回文子串的长度.对于该问题的求解,网上解法颇多,时间复杂度也不尽相同,这里列述几种常见的解法. 解法一       通过枚举S的子串,然后判断该字串是否为回文,由于S的子串个数大约为,加上每次判断需要的时间,所以总的时间复杂度为,空间复杂度为. bool check(string &S, int l

Keep Moving的专栏 1285

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

浅谈扩展KMP

扩展KMP问题 给定母串ss,和子串tt,定义n=|s|,m=|t|n=|s|,m=|t|,extendi=s[i..n]与t的最长公共前缀长度,快速求出所有的extendextend_i=s[i..n]与t的最长公共前缀长度,快速求出所有的extend。 引例 s=′aaaaabaa′s='aaaaabaa' t=′aaaaaa′t='aaaaaa' 首先通过六次运算,我们得到了e

gankinghand的博客 452

老版QQ原生表情gif动态

这是老版的QQ表情,不过全是动态的的,Windows照片查看器是不会动的,可以右击用浏览器打开查看,再说一遍是老版的,只是分享给宁愿用老版也要动态的人。

浅谈kmp

KMP算法:字符串匹配的优雅解法在计算机科学领域,字符串匹配是一项基础且重要的任务。KMP算法作为其中的经典算法,以其线性时间复杂度o(n+m)的卓越性能闻名KMP算法的核心在于构建部分匹配表(失败指针表),即所谓的next数组。这个数组记录了模式串中每个位置之前的子串的最长相同前缀后缀长度。构建过程采用动态规划思想,通过模式串自身的字符特性推导得出。构建步骤解析://求next数组(即寻找每个位置最大前缀后缀的位置)//next数组一开始全为0;i <= lb;i++)

2301_79696736的博客 917

HDU 4333 浅谈扩展KMP 线性求NXT数组模板

世界真的很大 对于把这道题当做扩展kmp的入门题的人们,有几句话我是一定要说的。 这道题不用求extand! 这道题不用求extand! 这道题不用求extand! 看了网上的几篇博客之后一直是晕的,不知怎么的他们的exkmp函数和我理解的kmp都不一样,以至于我都开始怀疑自己的理解了。。。 自己静下心来,好好分析了一遍题目后才发现,被坑了。其实根本没有求exkmp的步骤,仅对于这道题而

BerryKanry的博客 464

BZOJ 3670 浅谈KMP算法的拓展应用

世界真的很大 KMP处理字符串的匹配问题是非常熟悉的 KMP算法很独特的地方在于其失配指针,nxt数组,这个在其他字符串处理算法中也有应用 深刻理解nxt数组的实际意义对题目有时会有很大帮助 nxt数组不光是失配位置而已 这道题好写好调 看题先: description:近日,园长发现动物园中好吃懒做的动物越来越多了。例如企鹅,只会卖萌向游客要吃的。为了整治动物园的不良风气,让动物们凭

BerryKanry的博客 520

浅谈拓展kmp(z函数)

先贴一波kmp和manacher的博客,对于理解这个很有用: https://blog.youkuaiyun.com/qq_49593247/article/details/120077670?spm=1001.2014.3001.5501 拓展kmp函数(z函数)在竞赛中比较冷门,但是学习了z函数会提升对于manacher和kmp这一类的字符串处理算法的理解.它本身其实也是按照的kmp的思想. 扩展KMP求的是对于文本串S1的每一个后缀子串与模式串S2的最长公共前缀,类似于manacher算法,它也会存一个右端

qq_49593247的博客 433

浅谈KMP

给你一个文本串和一个模式串,问在文本串中模式串在什么时候出现过。 显然存在一种暴力写法(万能暴力): 从文本串和模式串的开头进行匹配,直到失配,则从模式串开头进行重新匹配。 显然这种写法是很慢的,失配后它只能一格一格地从头开始找。 看下面的例子: 当匹配到以下情况: 那么按照我们的暴力写法,应该是这个样: 它显然是匹配不上的嘛,只能一步步接着跑了,我们当然希望程序能聪明一点. ...

weixin_33769125的博客 93

浅谈字符串算法及练习题

本文介绍了四种字符串处理技术:哈希、字典树、Manacher和KMP算法。哈希通过固定转换将字符串映射为唯一值,用于快速检索;字典树以空间换时间,高效处理字符串前缀;Manacher算法利用动态规划寻找最长回文子串;KMP通过next数组优化字符串匹配。文章还提供了相关练习题及代码实现,如利用哈希统计子串、使用KMP求重复子串的最小长度等。最后作者幽默吐槽"我讨厌哈希",但全文内容详实,涵盖算法原理、代码实现和应用场景。

adminh_miao的博客 194

[置顶]【算法教程合集】

又又实在是太懒啦!!! 自己写学习笔记?不存在的。。。 在这里总结一下OI的一些教程(已分类)。 基础算法 离线算法 数据结构 线性结构 偏序维护 Math 数论 组合计数 置换群 多项式 从多项式乘法到快速傅里叶变换(FFT &amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp; NTT &amp;amp;amp;amp;amp;amp;amp;

又又大柚纸的博客 1306

浅谈第二阶段刷力扣的体验

如何进行刷力扣呢?怎么刷题才算刷题?这是我的现阶段刷力扣题型的总结和体会,希望能够帮助到大家。

蜡笔小新1980的博客 235

【字符串算法2】浅谈Manacher算法

【字符串算法1】 字符串Hash(优雅的暴力) 【字符串算法2】Manacher算法 【字符串算法3】KMP算法 这里将讲述字符串算法2:Manacher算法 问题:给出字符串S(限制见后)求出最大回文子串长度 Subtask1 对于10%的数据|S|∈(0,100] Subtask2 对于30%的数据|S|∈(0,5000] Subtask3 对于100%的数据...

weixin_30449453的博客 270

浅谈AC自动机 个人模板与说明

在下曾学习于 AC自动机详细讲解 必备技能: trie + KMP 文章目录1. 结构体2. 添加模式串3. 求失配指针4. 匹配文本串ends: 1. 结构体 cnt记录该结点的单词数,fail失配,son为子结点 struct node{ ll cnt,fail,son[26]; }a[manx]; 2. 添加模式串 void add(string s){ ll n=s...

放荡者的茶会 1079

BZOJ2384:[CEOI2014]Match

浅谈\(KMP\):https://www.cnblogs.com/AKMer/p/10438148.html 题目传送门:https://lydsy.com/JudgeOnline/problem.php?id=2384 这是一种特殊的\(KMP\)。匹配不再是直接判断相等了。 假设现在\([1,j]\)和\([i-j,i-1]\)已经匹配上了,我要判断\(j+1\)与\(i\)是否能...

aga28832的博客 244
上一篇: [SPOJ375] QTREE - Query on a tree
zyg0121
博客等级 码龄10年 13粉丝 39原创
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值