初识KMP算法

news2024/11/25 13:18:14

目录

1.KMP算法的介绍

2.next数组

3.总结


1.KMP算法的介绍

首先我们会疑惑,什么是KMP算法?这个算法是用来干什么的?

KMP(Knuth-Morris-Pratt)算法是一种用于字符串匹配的经典算法,它的目标是在一个主文本串(text)中查找一个模式串(pattern)的出现位置。KMP 算法通过利用模式串本身的特性,在匹配过程中避免回溯文本串的指针,从而达到快速匹配的目的。

KMP 算法的关键在于构建一个部分匹配表(Partial Match Table),

通常称为「next 数组」。这个表记录了模式串中每个位置对应的最长相同前缀后缀的长度。利用这个表,算法可以在匹配过程中智能地调整模式串的位置,避免不必要的比较,从而提高了匹配效率。

我们可以试想,当我们想将一个模式串遇主串匹配,并且找到模式串在主串中出现的第一个位置,通常我们会想到暴力求解。就是使用两个for循环,第一次for循环从主串的第一个元素开始遍历,当这时这个元素与模式串的第一个元素相同,那么我们就继续比对下一个元素,依次进行来找到模式串在主串出现的第一个元素,但是暴力求解的时间复杂度是(n*m),n是主串的长度,m是模式串的长度。

但是KMP算法可以将时间复杂度缩减到(n+m),大大节省了程序运行时间。

我们现在先来看一下KMP算法是如何匹配字符串,可以将时间复杂度缩减到(n+m)的。

面对上面这两个字符串的比对,我们会发现,在第一次比对时,只有最后一个元素不同,按照暴力算法是将子串与主串的第二个元素重新比对,但是KMP算法却不是这样比对,而是直接与主串的第三个元素比对,这时发现成功匹配。

那么我们应该怎么知道该将子串前进几个元素重新与主串比对呢?

这就需要我们引入一个next数组,前进几个元素取决于当出现不匹配的元素的前一个元素的所对应的next数组值。

2.next数组

1.构建部分匹配表(next 数组):遍历模式串,对每个位置计算最长相同前缀后缀的长度。这个长度表示了在当前位置失配时,应该移动模式串的位置以继续匹配。

那么什么是前后缀数组呢?

首先给出示例字符串:ababcbcab

它的前缀集合:{a,ab,aba,abab,ababc,ababcb,ababcbc,ababcbca}

它的后缀集合:{a,ab,cab,bcab,cbcab,bcbcab,abcbcab,babcbcab}

注意不能算是它本身,不然最长长度一直都是自己了。

看了上面的示例,那么对前后缀有了一个清晰的认识了吧!

这里相同的前后缀是ab,它的长度是2,那么此时的next数组里面是2。

现在给出求next数组的代码:

void get_next() //求出next数组 
{ 
    int i=0,j=-1;
    next1[0]=-1;
    while(i<len2) 
        if(j==-1 || s2[i]==s2[j]) 
            next1[++i]=++j;
        else j=next1[j];
} 

我们现在给出一个示例字符串:ABABACAB

1.第1个元素直接是0。

2.第2个元素的前缀合集合是{A},后缀是{B},没有共同,第二个是0。

3.第3个元素的前缀合集合是{A,AB},后缀是{A,BA},有相同的"A",那么是1。

4.第4个元素的前缀合集合是{A,AB,ABA},后缀是{B,AB,BAB},相同的是"AB",那么是2。

5.第5个元素的前缀合集合是{A,AB,ABA,ABAB},后缀是{A,BA,ABA,BABA},相同的是"ABA",那么是3。

6.第6个元素的前缀合集合是{A,AB,ABA,ABAB,ABABA},后缀是{C,AC,BAC,ABAC,BABAC},没有相同的,那么是0。

7.第7个元素的前缀合集合是{A,AB,ABA,ABAB,ABABA,ABABAC},后缀是{A,CA,ACA,BACA,ABACA,BABACA},相同的是"A",那么是1。

8.第8个元素的前缀合集合是{A,AB,ABA,ABAB,ABABA,ABABAC,ABABACA},后缀是{B,AB,CAB,ACAB,BACAB,ABACAB,BABACAB},相同的是"AB",那么是2。

那么我们计算出的next数组是:0 0 1 2 3 0 1 2

现在我们看代码运行结果。

代码计算出来也与我们手算的结果一样。

3.总结

匹配过程:在主文本串中从左往右逐个字符地与模式串进行比较。当发生不匹配时,根据部分匹配表的值来移动模式串的位置,而不是直接回溯到起始位置重新开始比较。

这时我们看看KMP的核心代码:

void KMP() //KMP 
{ 
    int i=0,j=0;//从第一个元素开始匹配 
    while(i<len1) 
    { 
        if(j==-1 || s1[i]==s2[j]) //匹配成功 
            i++,j++;
        else j=next1[j]; //失配 
        if(j==len2)
		{
			cout<<i-len2+1<<endl;//此时i-len2+1为匹配成功的第一个元素位置 
			j=next1[j];//匹配成功,再失配 
		} 
    }  
} 

总的来说,KMP 算法通过预处理模式串构建部分匹配表,然后利用这个表在匹配过程中避免不必要的回溯,从而提高了字符串匹配的效率。

下面我们可以做一道题来巩固我们的学习结果。

P3375 【模板】KMP - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

输入数据:

ABABABC
ABA

下面AC完整代码:

#include<bits/stdc++.h>
using namespace std;
int len1,len2;
int next1[1000001];
char s1[1000001];
char s2[1000001];
void get_next() //求出next数组 
{ 
    int i=0,j=-1;
    next1[0]=-1;
    while(i<len2) 
        if(j==-1 || s2[i]==s2[j]) 
            next1[++i]=++j;
        else j=next1[j];
} 
void KMP() //KMP 
{ 
    int i=0,j=0;//从第一个元素开始匹配 
    while(i<len1) 
    { 
        if(j==-1 || s1[i]==s2[j]) //匹配成功 
            i++,j++;
        else j=next1[j]; //失配 
        if(j==len2)
		{
			cout<<i-len2+1<<endl;//此时i-len2+1为匹配成功的第一个元素位置 
			j=next1[j];//匹配成功,再失配 
		} 
    }  
} 
int main(){ 
    cin>>s1>>s2;
    len1=strlen(s1);
    len2=strlen(s2);
    get_next();
    KMP();
    for(int i=1;i<=len2;++i) 
        cout<<next1[i]<<" ";//输出next数组 
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1457161.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Allegro172版本如何用自带功能改变过孔网络属性操作指导

Allegro172版本如何用自带功能改变过孔网络属性操作指导 在用Allegro做PCB设计的时候,时常会需要将过孔的网络进行变更,可以将原来的过孔删除,再重新打一个,这种方法难免会繁琐一些。 当然我们可以借助skill工具来完成更换过孔网络的更改,除此之外,Allegro自带的功能完成…

Excel常用快捷键(持续更新)

引言 excel是我们办公中经常使用的工具&#xff0c;古语言“工欲善其事必先利其器”。excel是一个好的工具&#xff0c;但是工具里面有很多常用的快捷键&#xff0c;若我们熟记这些快捷键&#xff0c;便可以提高我们的工作效率。本文为持续更新&#xff0c;望有助于搬砖。 1、C…

简单的线程池——从单线程到多线程——从零基础到零基础(站长素材)

多进程&#xff08;Process&#xff09;-读取到数据&#xff0c;要用cpu来运行大量的次数和时间&#xff08;多线程&#xff09;&#xff08;cpu密集型&#xff09;——multiprocessing 多线程&#xff08;Thread&#xff09;-IO多的&#xff0c;同时运行任务数目不多&#xf…

stm32学习笔记-STLINK使用

stm32学习笔记-STLINK使用 使用ST-LINK调试程序进度表格 使用ST-LINK调试程序 说明 组成 总结 记录使用STLINK进行项目的烧写和调试&#xff0c;旨在高效的进行代码调试学习工具包括笔记本、keil5MDK、stm32f030c8t6电表主机、STLINK V2、导线、电表代码总的来说&#xff0…

Kernel 地图

前言 在 Linux Kernel 中&#xff0c;根据 Makefile 和 Kconfig&#xff0c;可以快速地了解一个小的内核子系统。所以我将这两个文件称之为 Kernel 地图。 Kernel 地图 基本上&#xff0c;Linux 内核中&#xff0c;每一个目录下面都有一个 Makefile 和一个 Kconfig 文件。这…

ubuntu 之 zeitgeist-fts 占用内存

座右铭&#xff1a;怎么简单怎么来&#xff0c;以实现功能为主。 欢迎大家关注公众号与我交流 sudo chmod -x /usr/bin/zeitgeist-daemonsudo chmod -x /usr/bin/zeitgeist-datahublocate zeitgeist-ftssudo chmod -x /usr/lib/x86_64-linux-gnu/zeitgeist-fts # 使用 locate z…

星纪魅族宣布 All in AI;欧盟将首次对苹果处以罚款丨 RTE 开发者日报 Vol.146

开发者朋友们大家好&#xff1a; 这里是 「RTE 开发者日报」 &#xff0c;每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE &#xff08;Real Time Engagement&#xff09; 领域内「有话题的 新闻 」、「有态度的 观点 」、「有意思的 数据 」、「有思考的 文…

125.乐理基础-五线谱-大六度、小六度

内容参考于&#xff1a;三分钟音乐社 上一个内容&#xff1a;124.乐理基础-五线谱-大三度、小三度-CSDN博客 上一个内容里练习的答案&#xff1a; 然后g1到降e2是一个六度&#xff0c;g1到e2也是一个六度&#xff0c;但是它们俩距离是不一样的 然后在六度前面加上大或小&…

盲盒小程序开发:创新科技与消费者心理的完美结合

随着科技的飞速发展&#xff0c;小程序已经深入到我们生活的方方面面。而在众多小程序中&#xff0c;盲盒小程序以其独特的魅力&#xff0c;吸引了大量消费者的关注。本文将探讨盲盒小程序的发展背景、市场需求、开发流程以及未来趋势&#xff0c;以期为相关行业的从业者提供一…

mybatis-plus(五)-mybatis处理多数据源

mybatisplus多数据源 引入依赖 <dependency><groupId>com.baomidou</groupId><artifactId>dynamic-datasource-spring-boot-starter</artifactId><version>2.5.6</version> </dependency>配置文件 创建一个数据用户&#x…

【XR806开发板试用】+移植rosserial到XR806

1 XR806简介 板子来源于极术社区的试用&#xff0c;XR806的在线网址 其主要参数&#xff1a; 主控XR806AF2LDDRSIP 288KB SRAM存储SIP 160KB Code ROM. SIP 16Mbit Flash.天线板载WiFi/BT双天线&#xff0c;可共存按键reboot按键 1&#xff0c;功能按键 1灯红色电源指示灯 1…

快速部署MES源码/万界星空科技开源MES

什么是开源MES软件&#xff1f; 开源MES软件是指源代码可以免费获取、修改和分发的MES软件。与传统的商业MES软件相比&#xff0c;开源MES软件具有更高的灵活性和可定制性。企业可以根据自身的需求对软件进行定制化开发&#xff0c;满足不同生产环境下的特定需求。 开源MES软件…

three.js 物体下落动画(重力加速度)

效果&#xff1a; <template><div><el-container><el-main><div class"box-card-left"><div id"threejs" style"border: 1px solid red"></div><el-button click"loopFun"> 物体下落…

Java 基于 SpringBoot+Vue 的高校招生系统,附源码

博主介绍&#xff1a;✌程序员徐师兄、7年大厂程序员经历。全网粉丝12w、csdn博客专家、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末获取源码联系&#x1f345; &#x1f447;&#x1f3fb; 精彩专栏推荐订阅&#x1f447;…

Java学习--黑马SpringBoot3课程个人总结-2024-02-14

1.子路由 //定义路由关系 const routes[{ path: /login, component: LoginVue},{ path: /, component: LayoutVue,redirect:/article/manage,children:[{path:/article/category,component:ArticleCategoryVue},{path:/article/manage,component:ArticleManageVue},{path:/…

【漏洞复现-通达OA】通达OA share身份认证绕过漏洞

一、漏洞简介 通达OA(Office Anywhere网络智能办公系统)是中国通达公司的一套协同办公自动化软件。通达OA /share/handle.php存在一个认证绕过漏洞,利用该漏洞可以实现任意用户登录。攻击者可以通过构造恶意攻击代码,成功登录系统管理员账户,继而在系统后台上传恶意文件控…

Transformer位置表示(Position Encoding)

为什么需要位置表示 对比CNN、RNN和Self-Attention: CNN处理相邻窗口的内容&#xff1b;RNN天然是序列操作&#xff0c;考虑了位置先后关系&#xff1b;Self-Attention的计算时是无序的&#xff0c;所以需要位置表示来知道Token之间的位置信息。 绝对位置表示 典型如&#xf…

数据结构中图的概念以及遍历算法的实现

在数据结构中&#xff0c;图&#xff08;Graph&#xff09;是由节点&#xff08;Vertex&#xff09;和连接节点的边&#xff08;Edge&#xff09;组成的一种非线性数据结构。图可以用来表示各种实际问题中的关系和连接&#xff0c;如社交网络、道路网络、电路等。 图由两个主要…

LiveGBS流媒体平台GB/T28181常见问题-基础配置流媒体服务配置中本地|内网IP外网IP(可选)外网IP收流如何配置

LiveGBS常见问题基础配置流媒体服务配置中本地|内网IP外网IP外网IP收流如何配置&#xff1f; 1、流媒体服务配置2、播放提示none rtp data receive3、多网卡服务器4、收流端口配置5、端口区间可以如何配置6、搭建GB28181视频直播平台 1、流媒体服务配置 LiveGBS中基础配置-》流…

【小呆的力学笔记】弹塑性力学的初步认知五:初始屈服条件(1)

文章目录 3. 初始屈服条件3.1 两个假设以及屈服条件基本形式3.2 π \pi π平面、Lode参数3.3 屈服曲线的一般特征 3. 初始屈服条件 3.1 两个假设以及屈服条件基本形式 在简单拉伸时&#xff0c;材料的屈服很明确&#xff0c;即 σ > σ s (1) \sigma\gt\sigma_s\tag{1} …