KMP算法图文详解

2023-05-16

简介:

        Knuth-Morris-Pratt(KMP算法or字符串查找算法)可在一较长串S内查找一子串P出现的位置,KMP算法利用最长公共前后缀的特性以避免重新检索先前配对的字符串,提高算法效率。

——KMP算法最终由Knuth-Morris-Pratt三人于1977年联合发表

朴素算法(Brute Force Algorithm):

代码示例:

#include<iostream>
#include<cstring>
//i和j下标从0开始的情况:
using namespace std;

const int Max = 1e3 + 10;
int main() {
	char s[Max]={}, p[Max]={};

	cout << "请输入文本串S" << endl;
	cin >> s;
	cout << "请输入模式串P" << endl;
	getchar();
	cin >> p;


	int i = 0, j = 0;
	int sLen = strlen(s), pLen = strlen(p);

	while (i < sLen && j < pLen) {
		if(s[i] == p[j]){//如果匹配成功,i和j同步后移
			i++;
			j++;
		}
		else {//如果失配,i回溯,j归零
			i = i - (j - 1);
			//注意,i回溯到了最初始匹配成功的i的下一位;
			//最初始匹配成功:上一次匹配失败的下一位的i;
			j = 0;
		}
	}

	//如果匹配成功,则j等于pLen;
	if (j == pLen) cout << "匹配成功,物理位置为:" << i - j 
		<<" " << "逻辑位置为:" << i - j + 1 << endl;
	else cout << "抱歉,匹配失败!" << endl;
	return 0;
}

例如:查找串S为:ABCABCDAB 模式串P为:ABCD

注意:这里规定二者下标均从0开始

查找过程中:下标i从0开始,P串下标j从0开始;(下文会详解)

        

要想查找P在S中的位置,该如何查找呢?

假设此时:S和P都查找到了下标为2(逻辑地址,i = 1)的位置:因为S[i] == P[j],故i++,j++;

假设此时:S和P都查找到了下标为6的位置:但S[i] != P[j]; 此时:i = 5,j = 5

按照朴素算法,应该这样操作:令 i = i - j + 1 ,j = 0;(i的回溯过程)

此时 i = 5 - 5 + 1 = 1,i = 1,j = 0 ,相当于模式串P右移:S[i] != P[j];

此时 i = 1 - 0 + 1 = 2,i = 2,j = 0 ,相当于模式串P右移:S[i] != P[j];

此时 i = 2 - 0 + 1 = 3,i = 3,j = 0 ,由于:S[i] == P[j];   则:i++,j++;

 直到:i = 6 , j = 3;由于S[i] != P[j]; 此时 i = 6 - 3 + 1 = 4 , j = 0 ;相当于模式串P右移:

以此类推,直到 i = 9 ,由于 j = 5 即 N - 1 ; 所以查找到模式串;

KMP算法(KMP Algorithm):

代码示例:

#include<iostream>
#include<cstring>

using namespace std;
//求next数组:
void GetNext(char* p, int next[]) {
	int pLen = strlen(p);
	next[0] = -1;
	int k = -1, j = 0;//p[k]表示前缀,p[j]表示后缀
	while (j < pLen - 1) {
		if (k == -1 || p[j] == p[k]) {
			j++;
			k++;
			next[j] = k;
		}
		else {
			k = next[k];//模式串的自我匹配过程
		}
	}
}
const int Max = 1e3 + 10;
int main() {
	char s[Max] = {}, p[Max] = {};

	int next[Max] = {};
	GetNext(p, next);

	cout << "请输入文本串S" << endl;
	cin >> s;
	cout << "请输入模式串P" << endl;
	getchar();
	cin >> p;


	int i = 0, j = 0;
	int sLen = strlen(s), pLen = strlen(p);

	while (i < sLen && j < pLen) {
		if (s[i] == p[j] || j == -1) {//如果匹配成功 or j == -1,i和j同步后移
			i++;
			j++;
		}
		else {//如果失配,i不变,j = next[j];
			j = next[j];//相当于模式串p右移了j-next[j]位;
		}
	}

	//如果匹配成功,则j等于pLen;
	if (j == pLen) cout << "匹配成功,物理位置为:" << i - j
		<< " " << "逻辑位置为:" << i - j + 1 << endl;
	else cout << "抱歉,匹配失败!" << endl;
	return 0;
}

引言:

因此我们发现,朴素算法的效率比较低,尤其是第一步:

我们发现在ABCAB(下标1-5)中:

AB(下标12)作为前缀与作为后缀的AB(下标45)共同构成了最长(长度为2)的公共前后缀

因此,我们只需要:令 j = 2 ,相当于向右移动模式串3位(j = 5 ,j - 2 = 3);

这样以来,大大节省了匹配速度,面对失配情况,我们可以通过模式串P对应位的最长公共前后缀的长度,进行快速移位。不再需要像朴素算法那样,进行i的回溯和j的归零。

KMP算法的难点在于next数组的理解和构建

引入next数组:

引言我们可知:模式串P的第5位:对应的最长公共前后缀为2;

因此我们可以先求得该位置的最长公共前后缀:

模式串P[N]ABCABD
下标值123456
最大公共前后缀000120
next数组-100012

前缀:例如:ABCDA :不包括最后一个字符A的所有字符组合:A,AB,ABC,ABCD

后缀:例如:ABCDA :不包括最前一个字符A的所有字符组合:A,AD,ADC,ADCB

则,ABCDA的公共前后缀为:A,其中最长的为A,故ABCDA的最长公共前后缀为A;

显而易见,next 数组相当于“最大长度值” 整体向右移动一位,然后初始值赋为 -1。

KMP查找模式串:

由引言和引入next数组可知:遇到s[i]  != p[j]的情况,我们可以令j = next[j];

令j = next[j] ,相当于保持查找串S不动,模式串P右移了(j - next[j])位;

相当于前缀为1,后缀为2,将1的位置平移至3的位置; 

next[5] = 2,令 j = next[5] = 2,则模式串P右移了(5-2)位;

KMP查找代码如下:

while (i < sLen && j < pLen) {
		if (s[i] == p[j] || j == -1) {//如果匹配成功 or j == -1,i和j同步后移
			i++;
			j++;
		}
		else {//如果失配,i不变,j = next[j];
			j = next[j];//相当于模式串p右移了j-next[j]位;
		}
	}

求解next数组的值:

求解next数组和KMP查找差不多,只不过KMP查找是S[i]在P[j+1]之间查找;

求解next数组是模式串的自我匹配过程

求解next数组代码如下:​​​​​​​

void GetNext(char* p, int next[]) {
	int pLen = strlen(p);
	next[0] = -1;
	int k = -1, j = 0;//p[k]表示前缀,p[j]表示后缀
	while (j < pLen - 1) {
		if (k == -1 || p[j] == p[k]) {
			j++;
			k++;
			next[j] = k;
		}
		else {
			k = next[k];//模式串的自我匹配过程
		}
	}
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

KMP算法图文详解 的相关文章

  • 解决Maven的project标签(爆红) 插架无法导入

    目录 问题描述 解决方案 1 利用开发工具 idea 自动导入 2 pom依赖自动导入 错误原因 解决问题 3 网站下载插件 4 去本地仓库解决插件报红状态 4 1错误原因 4 2解决方法 问题描述 在拉取项目的时候project标签报错
  • typora全局替换文本

    主要讲解在typora中如何将整个文档中所有的字段替换为另一个字段 例如对于下面的句子 xff0c 需要把 曲面重建 全部改为 曲面三维重建 首先按ctrl 43 f打开全局搜索框 xff0c 在最顶上会弹出 xff0c 在这里输入需要替换
  • linux网络编程实践-linux应用编程和网络编程第9部分-朱有鹏-专题视频课程

    linux网络编程实践 linux应用编程和网络编程第9部分 14177人已学习 课程介绍 本课程是网络编程实践部分 xff0c 带大家使用socket接口及其相关函数 xff0c 从头编写一个服务器和客户端的通信程序 xff0c 并且引出
  • 链路聚合的原理以及配置

    链路聚合的原理以及配置 一 链路聚合的概述二 链路聚合的原理三 链路聚合的配置 一 链路聚合的概述 链路聚合 xff08 Link Aggregation xff09 是将两个或更多数据信道结合成一个单个的信道 xff0c 该信道以一个单个
  • 关于逻辑回归完成手写数字识别的一点愚蠢错误回顾

    最近的机器学习课上作业里要我们完成通过神经网络和逻辑回归进行手写数字的识别任务 xff0c 神经网络的部分通过课上的辅助教材 xff1a 神经网络与深度学习 其中所提供的代码足以完成 xff0c 另外这本书真的写的很好 xff0c 在易读性
  • OpenCV安装及其开发环境配置(C++)

    目录 第一章 Opencv安装及其环境变量配置 1 1下载并安装OpenCV 1 2 OpenCV环境变量配置 第二章 Visual Studio 2019 编译器下载安装 第三章 OpenCV开发环境配置 C 43 43 3 1创建项目
  • 目标检测中的anchor-base与anchor-free

    前言 本文参考目标检测阵营 Anchor Base vs Anchor Free 如何评价zhangshifeng最新的讨论anchor based free的论文 知乎 基础知识 目标检测中Anchor的认识及理解 目标检测领域的发展从a
  • 【论文合集】RGBD Semantic Segmentation

    来源 xff1a GitHub Yangzhangcst RGBD semantic segmentation A paper list of RGBD semantic segmentation processing RGBD seman
  • webpack实战(巨详细)

    先附上官网地址 xff1a 概念 webpack 中文网 了解下概念后 xff0c 一起开始webpack之旅吧 一 开始 首先在安装之前 xff0c 需要安装node xff0c 因为webpack的运行是依赖Node环境的 xff0c
  • qcow2格式的虚拟机镜像转换为vdi格式

    VirtualBox不能直接操作qcow2镜像 xff0c 在Windows上暂时没有找到其他替代工具 xff0c 还是需要先有一个CentOS虚拟机来运行qemu img命令 将qcw2的镜像导入或通过挂载的方式传输到Centos的虚拟机
  • 简单的彩票小程序(双色球含机选及自选)

    话不多说直接上代码 package com import java util public class curriculum public static void main String args 机选 int times 61 100 L
  • IDEA设置JDK版本

    idea更换版本需全更改一致 鼠标点击file gt setting xff0c 进入idea的设置页面settings xff0c 根据截图操作 然后 xff0c 鼠标点击file gt Project Structure 1 7版本 1
  • 3步教会你使用VNC Viewer远程连接控制树莓派桌面(详细)

    目录 1 查询IP地址 1 1 路由器后台查询 1 2 树莓派内查询 2 开启VNC服务 3 打开VNC Viewer进行连接 1 查询IP地址 1 1 路由器后台查询 打开路由器后台 xff0c 我这以腾达为例 xff0c 在浏览器输入
  • 驱动应该怎么学-linux驱动开发第1部分-朱有鹏-专题视频课程

    驱动应该怎么学 linux驱动开发第1部分 4059人已学习 课程介绍 本课程是linux驱动开发的第一个课程 xff0c 主要介绍linux驱动的概念 模块化设计理念 分类 安全性要求 xff0c 后讲解了linux驱动课程的整体学习方法
  • 安装DEV-C++5.11(无捆绑)

    安装网址 或者点这儿直接下载 xff09 DEV C 43 43 https pc qq com detail 16 detail 163136 html https pc qq com detail 16 detail 163136 ht
  • 中国大学慕课第7周测验

    1 单选 1分 写出下面程序的运行结果 include lt stdio h gt void Bin int x if x 2 gt 0 Bin x 2 printf 34 d n 34 x 2 int main Bin 12 return
  • 基于深度强化学习的智能船舶航迹跟踪控制

    基于深度强化学习的智能船舶航迹跟踪控制 人工智能技术与咨询 昨天 本文来自 中国舰船研究 xff0c 作者祝亢等 关注微信公众号 xff1a 人工智能技术与咨询 了解更多咨询 xff01 0 引 言 目前 xff0c 国内外对运载工具的研究
  • 面向区块链的高效物化视图维护和可信查询

    面向区块链的高效物化视图维护和可信查询 人工智能技术与咨询 来源 xff1a 软件学报 xff0c 作者蔡 磊等 摘 要 区块链具有去中心化 不可篡改和可追溯等特性 可应用于金融 物流等诸多行业 由于所有交易数据按照交易时间顺序存储在各个区
  • 基于迁移深度学习的雷达信号分选识别

    基于迁移深度学习的雷达信号分选识别 人工智能技术与咨询 来源 xff1a 软件学报 xff0c 作者王功明等 摘要 针对当前雷达信号分选识别算法普遍存在的低信噪比下识别能力差 特征参数提取困难 分类器模型参数复杂等问题 xff0c 提出了一
  • 基于深度学习的磁环表面缺陷检测算法

    基于深度学习的磁环表面缺陷检测算法 人工智能技术与咨询 来源 xff1a 人工智能与机器人研究 xff0c 作者罗菁等 关键词 缺陷检测 xff1b 深度学习 xff1b 磁环 xff1b YOLOv3 xff1b 摘要 在磁环的生产制造过

随机推荐

  • 基于PX4的地面无人车避障系统及路径规划研究

    基于PX4的地面无人车避障系统及路径规划研究 人工智能技术与咨询 来源 xff1a 动力系统与控制 xff0c 作者姜琼阁等 关键词 地面无人车 xff1b 避障 xff1b PX4 xff1b 摘要 地面无人车避障及路径规划是指 xff0
  • 基于图像的数据增强方法发展现状综述

    基于图像的数据增强方法发展现状综述 人工智能技术与咨询 2022 03 22 20 57 点击蓝字 关注我们 来源 xff1a 计算机科学与应用 xff0c 作者冯晓硕等 关键词 数据增强 xff1b 图像数据集 xff1b 图像处理 xf
  • 基于改进SSD算法的小目标检测与应用

    人工智能技术与咨询 点击蓝字 关注我们 来源 xff1a 计算机科学与应用 xff0c 作者刘洋等 关键词 SSD xff1b 深度学习 xff1b 小目标检测 摘要 xff1a 摘要 针对通用目标检测方法在复杂环境下检测小目标时效果不佳
  • 组网雷达融合处理组件化设计与仿真

    人工智能技术与咨询 点击蓝色 关注我们 关键词 xff1a 组网雷达 点迹融合 航迹融合 组件化设计 仿真 摘要 数据融合处理是多雷达组网的核心 以典型防空雷达网为参考对象 xff0c 采用组件化设计方式 xff0c 将组网数据融合处理过程
  • 字符设备驱动基础-linux驱动开发第2部分-朱有鹏-专题视频课程

    字符设备驱动基础 linux驱动开发第2部分 5673人已学习 课程介绍 本课程是linux驱动开发的第2个课程 xff0c 从零开始带领大家逐渐熟悉内核模块 xff0c 并且一步步写出一个字符设备驱动程序来控制LED等 本课程对驱动的学习
  • 人工智能 知识图谱

    关于举办 2022年数字信息化培训项目系列 知识图谱Knowledge Graph构建与应用研修班线上课程的通知 各有关单位 一 培训目标 本次课程安排紧密结合理论与实践 xff0c 深入浅出 xff0c 循序渐进 从基本概念讲起 xff0
  • 深度学习(Deep Learning)

    知识关键点 1 人工智能 深度学习的发展历程 2 深度学习框架 3 神经网络训练方法 4 卷积神经网络 xff0c 卷积核 池化 通道 激活函数 5 循环神经网络 xff0c 长短时记忆 LSTM 门控循环单元 GRU 6 参数初始化方法
  • 基于深度学习的机器人目标识别和跟踪

    如今 xff0c 深度学习算法的发展越来越迅速 xff0c 并且在图像处理以及目标对象识别方面已经得到了较为显著的突破 xff0c 无论是对检测对象的类型判断 xff0c 亦或者对检测对象所处方位的检测 xff0c 深度学习算法都取得了远超
  • 散列表与探测法

    动态查找的时候 如果用查找树同时对俩个变量名 字符串 进行查找 会导致效率不高的问题 引入散列的思想 把字符串变成数字 使得对字符串的比较变成对数字的比较 查找方式时间复杂度顺序查找O n 二分查找 静态查找 O log2N 二叉搜索树O
  • Springboot实现VNC的反向代理

    背景 用户需要通过前端HTML页面的noVNC xff08 noVNC是什么 xff1f xff09 客户端连接底层VNC Server服务端 xff0c 为了防止VNC Server的IP暴露 xff0c 因此需要做一层代理 正常情况下使
  • Visual Studio Code 的C++环境配置和调试

    目录 前言 xff1a 1 为什么要写这篇文章 xff1f 2 为什么选择VS Code xff1f 3 如何联系我 xff1f 简而言之 xff0c VS Code免费 43 快速 43 好用 43 潜力无穷 xff1b 一 安装VS C
  • 浅析向量(Vector),迭代器(Iterator)和数组(Array)

    目录 前言 Foreword 向量 Vector 1 何为向量 xff1f 2 如何初始化Vector向量 xff1f 3 向量的基本操作 xff1a 4 Range based For Statement 5 向量的插入操作 xff1a
  • 《数字电路分析》学习札记

    目录 前言 xff1a Chapter 1 数字逻辑基础 进制 xff1a 进制间转换方法 xff1a BCD xff1a 余3码 xff1a 余3循环码 xff1a 格雷码 xff08 循环码 xff09 xff1a 二进制数 格雷码 x
  • Ubuntu 22.04 双系统安装和卸载

    前言 xff1a 一 为什么选择Ubuntu系统 xff1f 1 免费且提供长期系统维护支持 xff1b 2 是主流的Linux服务器发行版 xff1b 3 强大的Shell xff1b 4 简洁好看的图形化UI界面 xff1b 5 丰富的
  • CSS-Div居中方法(Position方法)

    目录 代码展示 xff1a 实际效果 xff1a 具体分析 xff1a 如何联系我 xff1f 代码展示 xff1a lt DOCTYPE html gt lt html lang 61 34 en 34 gt lt head gt lt
  • 字符设备驱动-linux驱动开发第3部分-朱有鹏-专题视频课程

    字符设备驱动 linux驱动开发第3部分 4561人已学习 课程介绍 本课程是linux驱动开发的第3个课程 xff0c 接上部分继续讲解字符设备驱动的开发要点 xff0c 重点是相关的内核源代码的解析和一些真正驱动惯用的编程手法的引入 本
  • C++测试代码运行时间

    如果我们想直观地看出朴素算法和其他算法对程序运行时间的影响 xff0c 那么就可以采取以下方式 方法1 xff1a 基于头文件ctime和函数clock 的实现 代码1 xff1a include lt iostream gt includ
  • VMware虚拟机安装CentOS 7

    目录 1 VMware软件安装 2 CentOS 7 镜像下载 3 VMware安装CentOS 1 安装前内容设置 xff1a 2 安装中操作步骤 3 安装后语言设置 4 将图形化界面切换为命令符界面 如何联系我 xff1f wei ha
  • 解决Windows开机后无启动项的问题

    前言 为什么会出现这个问题 xff1f 此前PC上装有Windows 43 Ubuntu双系统 xff0c 由于又配置了虚拟机下的Centos xff0c 我把Ubuntu系统卸载了 没想到手滑删除了Windows的引导项 如图所示 xff
  • KMP算法图文详解

    简介 xff1a Knuth Morris Pratt xff08 KMP算法or字符串查找算法 xff09 可在一较长串S内查找一子串P出现的位置 xff0c KMP算法利用最长公共前后缀的特性以避免重新检索先前配对的字符串 xff0c