数据结构:KMP算法

1.何为KMP算法

     KMP算法是由Knuth、Morris和Pratt三位学者发明的,所以取了三位学者名字的首字母,叫作KMP算法。

2.KMP的用处

     KMP主要用于字符串匹配的问题,主要思想是当出现字符串不匹配时,我们可以知道一部分之前已经匹配过的的文本内容,利用这些信息从而避免从头再开始匹配。

     但是如何才能知道之前已经匹配过的内容呢?这是KMP算法的核心,也是KMP算法里面的next数组的用处。

3.最长相等前后缀

     一个字符串的前缀是指不包含最后一个字符的所有以第一个字符开头的连续字串

     后缀是指不包含第一个字符的所有以最后一个字符结尾的连续子串

     前缀表也就是next数组要求的是最长相等前后缀的长度,例如a的最长相等前后缀为0,aaa得到最长相等前后缀为2,aaba的最长相等前后缀为1。

4.next数组(前缀表)

     KMP的核心就是next数组,当模板串和主串不匹配时,next数组是用来让模板串知道应该从哪里再开始匹配。

     next数组记录下标i之前(包括i)的字符串中,有多大长度的相等前后缀。

     这里借用了代码随想录的图片

     比如我们要在文本串aabaabaafa中寻找模板串aabaaf,在b和f之前发现匹配不了,如果用暴力算法,就要从头开始匹配,文本串和模板串都需要进行回退,时间复杂度是很高的,但如果我们使用KMP算法,next数组记录了f之前有多大长度的相等前后缀,也就是我们知道了之前匹配过的内容,就会从上次已经匹配的内容开始匹配,这里为什么能这样呢?我是这样理解的:

     文本串: aabaabaafa  用i遍历

     模板串:aabaaf      用j遍历

     在b和f时不相同了,这时候我们不想再匹配我们已经匹配过的,也就是说我们不想i回退,而是一直向前走,那我们就要j进行回退,回退到什么位置呢,前面已经匹配到了,说明已经匹配过的文本串aabaa中含有模板串一部分内容,又因为前后缀有相等的部分。所以我们回退到前后缀相等的前缀位置,因为和文本串是相同的,所以aabaa的后缀aa和文本串的aabaa的后缀aa是相等的,又有aabaa的前缀aa和后缀aa是相等前后缀,所以前缀aa和文本串aabaa的后缀aa相等,我们回退到aabaa的b即可避免再次匹配aabaa的前缀aa,这样也可以保证模板串aabaa的前缀aa是已经匹配过的。

      f之前这部分的字符串(也就是字符串aabaa)的最长相等前后缀是aa ,因为找到了最长相等的前后缀,匹配失败的位置是后缀的后面,那么我们找到与其相同的前缀的后面重新匹配就可以了。

5.如何计算next数组

 例如a a b a a f

 下标0 1 2 3 4 5

next 0 1 0 1 2 0

     当下标为0时,长度为前1个字符的字串a,最长相等前后缀的长度为0

     当下标为1时,长度为前2个字符的字串aa,最长相等前后缀的长度为1

     依次类比,可以得到next数组,也就是前缀表

     可以看出模板串和next数组对应位置的数字表示的是下标i之前(包括i)的字符串中,有多大长度的最长相等前后缀。

      当我们找到不匹配的位置时,就要看它前一个字符的next数组的值是多少,因为我们要找前面字符串的最长相等前后缀,所以要看前一位的next数组的值,前一个字符的next数组值为2,所以我们把下标j移动到2的位置继续匹配,这样就可以匹配到了。

6.next数组实现

     主要是处理前后缀相等和不相等的情况,我们首先定义一个getNext函数来构造next数组,参数为指向next数组的指针,和一个字符串

void getNext(int* next,string& s)

     接着我们对其进行初始化,定义两个指针i和j,j指向前缀末尾,i指向后缀末尾,对next数组进行初始化赋值

int j=0;
next[0]=j;

     next[i]表示i(包括i)之前最长相等的前后缀长度,就是j,所以初始化next[0]=j

6.1前后缀不相同

     j=0,所以我们从i=1开始,遍历文本串,就像这样

for(int i=0;i<s.size();i++)

      j首先要保证是大于0的,因为下面j要回退,然后就是s[i]和s[j]的比较,如果s[i]和s[j]不相同,j就要找前一位对应的回退位置,因为这里j之前的前缀已经和i的后缀不相等了,所以我们就要j进行回退。

while(j>=0&&s[i]!=s[j])
{
   j=next[j-1];
}

 6.2前后缀相同

     如果是s[i]和s[j]相同,这时候只要同时移动i和j,这时候找到了相同的前后缀,我们要把j的值赋值给next[i],因为next[i]记录相同前后缀的长度

if(s[i]==s[j])
{
   j++;
}
next[i]=j;

      完整代码如下: 

void getNext(int* next, const string& s) 
{
     int j = 0;
     next[0] = 0;
     for(int i = 1; i < s.size(); i++) 
     {
        while (j > 0 && s[i] != s[j])
        { 
            j = next[j - 1]; 
        }
        if (s[i] == s[j])
        {
            j++;
        }
        next[i] = j;
     }
}

7.例题    

 

  void getNext(int* next,const string& s){
            int j=0;
            next[0]=0;
            for(int i=1;i<s.size();i++){
                while(j>0&&s[i]!=s[j]){
                    j=next[j-1];
                }
                if(s[i]==s[j]){
                    j++;
                }
                next[i]=j;
            }
        }
            int strStr(string haystack,string needle){
                if(needle.size()==0){
                    return 0;
                }
                int next[needle.size()];
                getNext(next,needle);
                int j=0;
                for(int i=0;i<haystack.size();i++){
                    while(j>0&&haystack[i]!=needle[j]){
                        j=next[j-1];
                    }
                    if(haystack[i]==needle[j]){
                        j++;
                    }
                    if(j==needle.size()){
                        return (i-needle.size()+1) ;
                 }
                }
                return -1;
            }

     这道题很明显是字符串匹配的问题,所以我们使用KMP算法,首先是next数组的构建,这是模板,直接写就行,然后就是模板串和文本串的匹配,如果不相同,那j就回退到next[j-1],如果相同,j就直接向后移动即可,当j和模板串的长度相等时,此时i一定是大于等于模板串的长度的,因为i之前的文本串是包含模板串的,所以我们用i-模板串的长度+1就是第一个匹配项的下标了。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

18.仿简道云公式函数实战-数学函数-AVERAGE

1. AVERAGE函数 AVERAGE 函数可用于计算一组数值的算术平均值。 2. 函数用法 AVERAGE(数字1,数字2,...) 3. 函数示例 AVERAGE(1,3,5)&#xff0c;返回结果为 3 4. 代码实战 首先我们在function包下创建math包&#xff0c;在math包下创建AvgFunction类&#xff0c;代码如…

戴口罩监测识别摄像机

随着冬季的到来&#xff0c;安分一段时间的病毒也慢慢的爆发&#xff0c;口罩作为一种重要的防护物品受到了广泛关注。为了加强对口罩佩戴情况的监测和识别&#xff0c;许多场所开始引入了戴口罩监测识别摄像机。这种摄像机通过图像识别技术可以自动检测出人们是否佩戴口罩&…

JAVA版的鸿鹄云商B2B2C:多商家入驻直播商城系统特性解析 商城免 费搭建

鸿鹄云商 b2b2c产品概述 【b2b2c平台】&#xff0c;以传统电商行业为基石&#xff0c;鸿鹄云商支持“商家入驻平台自营”多运营模式&#xff0c;积极打造“全新市场&#xff0c;全新 模式”企业级b2b2c电商平台&#xff0c;致力干助力各行/互联网创业腾飞并获取更多的收益。从消…

Php与Apache环境配置

Php与Apache环境配置 1.[Apache的下载安装&#xff1a;](https://blog.csdn.net/qq_42194657/article/details/102933368)2、PHP下载&#xff1a;2.1、下载地址&#xff1a;[http://php.net/downloads.php](http://php.net/downloads.php)2.1、版本选择&#xff1a;如果是与 Ap…

文本编辑器:Sublime Text (安装+汉化)

下载 Sublime Text - Text Editing, Done Righthttps://www.sublimetext.com/Sublime Text官网 支持mac&#xff0c;Linux&#xff0c;Windows 安装 选择安装路径 next install 选择安装位置安装就行了 汉化 进入了主界面按 CTRLshiftp 输入install 选择第一个 弹窗就按确…

系列六(实战)、发送 接收异步消息(Java操作RocketMQ)

一、发送 & 接收异步消息 1.1、概述 异步消息通常应用在对响应时间比较敏感的业务中&#xff0c;即发送端不能容忍长时间的等待Broker的响应&#xff0c;发送完成后会立即有一个异步消息通知。 1.2、Demo02MQTestApp /*** Author : 一叶浮萍归大海* Date: 2023/12/25 09…

养车平台源码定制化需求指南:10种实用功能一览

作为养车平台源码定制化领域的专家&#xff0c;我将向您介绍10种实用功能&#xff0c;帮助您更好地满足定制化需求&#xff0c;并提升用户体验。 1. 个性化主题定制 定制化养车平台源码可轻松实现个性化主题定制&#xff0c;包括颜色、字体、背景等&#xff0c;提供多样化选择…

MsSQL中的索引到底长啥样,查找过程怎么进行

参考文章一 参考文章二 建表 mysql> create table user(-> id int(10) auto_increment,-> name varchar(30),-> age tinyint(4),-> primary key (id),-> index idx_age (age)-> )engineinnodb charsetutf8mb4;insert into user(name,age) values(张三,…

数据安全:保护个人隐私和企业机密的关键

在当今数字化时代&#xff0c;数据已经成为了一种宝贵的资源。无论是个人还是企业&#xff0c;都离不开数据的支持。然而&#xff0c;随着数据的不断增长和广泛应用&#xff0c;数据安全问题也日益突出。数据泄露、黑客攻击、网络诈骗等安全事件层出不穷&#xff0c;给个人和企…

hash长度扩展攻击

作为一个信息安全的人&#xff0c;打各个学校的CTF比赛是比较重要的&#xff01; 最近一个朋友发了道题目过来&#xff0c;发现有道题目比较有意思&#xff0c;这里跟大家分享下 这串代码的大致意思是&#xff1a; 这段代码首先引入了一个名为"flag.php"的文件&am…

NFC读卡------ci522

1、NFC及卡片 NFC是近距离无线通讯技术&#xff0c;是一种非接触式识别和互联技术&#xff0c;可以在移动设备、消费类电子产品、PC和智能控件工具间进行近距离无线通信。NFC提供了一种简单、触控式的解决方案&#xff0c;可以让消费者简单直观地交换信息、访问内容与服务。 …

Java内存区域与内存溢出异常

Java与C++之间有一堵由内存分配和垃圾收集技术所围成的高墙,墙外面的人想进去,墙里面的人却想出来。 2.1 概述 对于从事C、C++程序开发的开发人员来说,在内存管理领域,他们即是拥有最高权力的“皇帝”,又是从事最基础工作的劳动人民——即拥有每一个对象的“所有权”,又…

用栈和队列分别实现求解迷宫问题(c++,c)

求解迷宫问题&#xff1a;给定一个迷宫要求输出其路径。 给出的迷宫如下&#xff08;可自行更改&#xff09; 可用两种方法实现1.栈2.队列 用栈只能找到路但路不是最简的最简的要用队列实现 用栈实现&#xff08;解析都在代码里了&#xff09; c&#xff08;实现&#xff0…

rhel7/centos7升级openssh到openssh9.5-p1

openssh9.3-p2以下版本有如下漏洞 在rhel7.4/7.5/7.6均做过测试。 本文需要用到的rpm包如下&#xff1a; https://download.csdn.net/download/kadwf123/88652359 升级步骤 1、升级前启动telnet ##升级前启动telnet服务 yum -y install telnet-server yum -y install xinetd…

四、UART_阻塞发送中断接收

1、开发环境 (1)Keil MDK: V5.38.0.0 (2)MCU: mm320163D7P 2、实验目的&原理图 2.1、实验目的 (1)上位机串口助手给MCU发送信息&#xff0c;MCU串口通过通过串口助手接收后&#xff0c;将接收到的内容通过串口助手发送到上位机。 (2)串口在whil循环中每隔1秒发送一次…

制作自己的 Docker 容器

软件开发最大的麻烦事之一&#xff0c;就是环境配置。用户必须保证操作系统的设置&#xff0c;各种库和组件的安装&#xff0c;只有它们都正确&#xff0c;软件才能运行。docker从根本上解决问题&#xff0c;软件安装的时候&#xff0c;把原始环境一模一样地复制过来。 以 koa-…

Python 序列之列表

系列文章目录 Python序列之元组 Python序列之列表 系列文章目录[TOC](Python序列之列表) 前言一、序列是什么&#xff1f;二、列表1.列表简介2.列表创建&#xff08;1&#xff09;[]创建&#xff08;2&#xff09;list创建&#xff08;3&#xff09;range()创建整数列表&#…

VS2010推荐字体设置

fixedsys excelsior是VS2010推荐字体。下载地址为 链接&#xff1a;https://pan.baidu.com/s/16OFbjBEF35zRfQe04Jfuag 提取码&#xff1a;wzjj下载成功后将ttf文件复制粘贴到C盘Windows中的font文件夹中自动安装指定字体&#xff0c;此时就可以在VS2010的工具&#xff0c;选…

多维时序 | MATLAB实CNN-Mutilhead-Attention卷积神经网络融合多头注意力机制多变量时间序列预测

多维时序 | MATLAB实CNN-Mutilhead-Attention卷积神经网络融合多头注意力机制多变量时间序列预测 目录 多维时序 | MATLAB实CNN-Mutilhead-Attention卷积神经网络融合多头注意力机制多变量时间序列预测预测效果基本介绍模型描述程序设计参考资料 预测效果 基本介绍 多维时序 | …

下定决心了,从字节跳动离职

今天在脉脉上看到这么一条内容&#xff1a; 看完感触很深&#xff0c;想起了我在帝都上班的那几年时光。 我记得我去帝都上班的时候&#xff0c;第一次坐帝都的地铁&#xff0c;那时候是找工作面试&#xff0c;在地铁里第一次感受到了大城市的上班速度&#xff0c;每个人都急匆…