数据结构中的KMP算法及其改进算法

数据结构中的KMP算法及其改进算法

在计算机科学中,字符串匹配是一个基本且重要的问题。经典的暴力匹配算法虽然简单,但在最坏情况下的时间复杂度为O(mn),其中m是模式串的长度,n是文本串的长度。为了提高匹配效率,Knuth-Morris-Pratt(KMP)算法应运而生,其时间复杂度为O(m+n),显著提升了匹配速度。本文将介绍KMP算法的基本原理及其改进算法。

KMP算法的基本原理

KMP算法的核心思想是利用部分匹配表(也称为next数组)来避免不必要的重复匹配。在进行字符串匹配时,KMP算法通过分析已经匹配的部分,决定接下来从哪里开始匹配,从而跳过一些已经确定不会匹配的字符。

步骤一:构建next数组

next数组记录了每个位置之前的部分匹配信息。具体来说,对于模式串P,next数组中的每个元素next[i]表示在位置i之前的模式串的最长相同前后缀的长度。

构建next数组的过程如下:

  1. 初始化:设定next[0] = -1,表示空字符串的前缀没有匹配。
  2. 迭代构建:使用双指针方法,一个指向当前字符,一个指向前缀的结束位置,逐步计算每个位置的next值。
void computeNextArray(const string &P, vector<int> &next) {int m = P.size();int j = 0;  // 前缀末尾指针int k = -1; // 前缀开始指针next[0] = -1;while (j < m - 1) {if (k == -1 || P[j] == P[k]) {j++;k++;next[j] = k;} else {k = next[k];}}
}

步骤二:进行字符串匹配

利用next数组进行匹配时,避免了暴力算法中的重复检查。在匹配过程中,遇到不匹配字符时,根据next数组跳转到适当的位置继续匹配。

int KMP(const string &T, const string &P) {int n = T.size();int m = P.size();vector<int> next(m);computeNextArray(P, next);int i = 0; // 文本串指针int j = 0; // 模式串指针while (i < n) {if (j == -1 || T[i] == P[j]) {i++;j++;} else {j = next[j];}if (j == m) {return i - j; // 匹配成功,返回起始位置}}return -1; // 匹配失败
}
KMP算法的改进

KMP算法尽管已经非常高效,但在构建next数组时仍有改进空间。原始的next数组中有部分重复计算,优化这些计算可以进一步提升效率。

改进的next数组(优化next数组)

改进后的next数组用next’表示,在构建过程中避免了多次回溯,通过调整指针逻辑,直接跳过不必要的匹配。

void computeNextArrayOptimized(const string &P, vector<int> &next) {int m = P.size();int j = 0;int k = -1;next[0] = -1;while (j < m - 1) {if (k == -1 || P[j] == P[k]) {j++;k++;if (P[j] != P[k]) {next[j] = k;} else {next[j] = next[k];}} else {k = next[k];}}
}

使用优化后的next数组进行匹配的主过程不变,但由于构建next数组的效率提高,总体性能会有所提升。

总结

KMP算法通过引入部分匹配表,有效避免了重复计算,从而将字符串匹配的时间复杂度降低到O(m+n)。通过进一步优化next数组,KMP算法的效率得到了进一步提升。对于大规模字符串匹配问题,KMP算法及其改进算法提供了高效的解决方案,是计算机科学领域的经典算法之一。

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

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

相关文章

最全的Redis常用命令

Redis是一个开源的内存数据结构存储系统&#xff0c;用作数据库、缓存和消息代理。它支持多种类型的数据结构&#xff0c;如字符串&#xff08;strings&#xff09;、哈希&#xff08;hashes&#xff09;、列表&#xff08;lists&#xff09;、集合&#xff08;sets&#xff09…

Spring Boot 系统学习第三天:Spring依赖注入原理分析

1.概述 Spring中关于依赖注入的代码实现非常丰富&#xff0c;涉及大量类和组件之间的协作与交互。从原理上讲&#xff0c;任何一个框架都存在一条核心执行流程&#xff0c;只要抓住这条主流程&#xff0c;就能把握框架的整体代码结构&#xff0c;Spring也不例外。无论采用何种依…

什么是容器

容器是一种用于存储、管理和运行应用程序的技术。它可以将应用程序及其依赖项打包到一个独立的可移植容器中&#xff0c;以便在不同的环境中进行部署和运行。容器化技术可以提供一种轻量级、快速、可移植的应用程序部署解决方案。 容器的背后核心概念是隔离。容器使用操作系统…

YoloV8改进策略:注意力改进|HCANet全局与局部的注意力模块CAFM|二次创新|即插即用

文章目录 摘要用在自己的论文中,该如何描述原论文中的描述在自己论文中描述代码与详解官方结果改进方法测试结果总结摘要 在CAFM模型的基础上进行二次创新,我成功地开发了一个性能显著提升的改进版模型。这一创新不仅优化了特征提取和融合的方式,还极大地提高了模型的泛化能…

.NET CORE 屏蔽重复提交

加入session支持 public void ConfigureServices(IServiceCollection services) {// add session supportservices.Configure<CookiePolicyOptions>(options >{options.CheckConsentNeeded context > false;options.MinimumSameSitePolicy Microsoft.AspNetCore.…

【C语言】自定义类型:联合与枚举的简明概述

&#x1f525;引言 关于自定义类型除了我们常用的结构体&#xff0c;还有联合与枚举也是属于自定义类型。本篇将简单介绍联合与枚举基本概念和使用方法 &#x1f308;个人主页&#xff1a;是店小二呀 &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;C笔记专栏&…

BMC术语

BMC&#xff08;Baseboard Management Controller&#xff09;&#xff0c;用来进行远程带外管理的设备&#xff0c;BMC 是独立于服务器系统之外的小型操作系统&#xff0c;是一个集成在主板上的芯片&#xff0c;也有产品是通过 PCIE 等形式插在主板上&#xff0c;对外表现形式…

[C++][Warning] Default arguments on virtual or override methods are prohibited

1 引言 C作为一门强大的编程语言&#xff0c;广泛用于开发各种类型的应用程序&#xff0c;特别是在面向对象编程领域。在C中&#xff0c;虚函数和重写函数是面向对象编程的关键概念&#xff0c;它们允许我们建立强大的继承层次结构和多态行为。默认参数则为函数提供了额外的灵…

《NoSQL数据库技术与应用》MongoDB数据库操作

《NoSQL数据库技术与应用》 教学设计 课程名称&#xff1a;NoSQL数据库技术与应用 授课年级&#xff1a; 20xx年级 授课学期&#xff1a; 20xx学年第一学期 教师姓名&#xff1a; 某某老师 2020年5月6日 课题 名称 第3章 MongoDB数据库操作 计划学时 14课时 内容 分析 如果说…

如何在.NET中集成SignalR

SignalR 简介 SignalR是一个开放源代码库&#xff0c;可用于简化向应用添加实时Web功能&#xff0c;实时Web功能使服务器端代码能够将内容推送到客户端。 SignalR开源库&#xff1a;https://github.com/SignalR/SignalR SignalR 应用场景 需要高频次从服务器获取信息的应用&am…

QML_Switch控件_3选2的控制算法

QML_Switch控件_3选2的控制算法 import QtQuick 2.12 import QtQuick.Window 2.12 import QtQuick.Controls 2.5Window {visible: truewidth: 400height: 400title: qsTr("Hello World")property int num: 0Row {spacing: 10Switch {id: switch1onCheckedChanged: {…

Android基础-初识Android系统架构

Android系统架构详解 Android系统作为一款广泛应用于智能手机、平板电脑等设备的操作系统&#xff0c;其架构的设计对于系统的稳定性、可扩展性和用户体验至关重要。Android系统架构是一个复杂的层次结构&#xff0c;旨在实现硬件与软件之间的高效协同工作&#xff0c;为用户提…

redis如何查看参数值

在Redis中&#xff0c;查看参数值可以使用CONFIG GET命令。以下是查看Redis参数值的详细步骤和格式化的回答&#xff1a; 1. 启动Redis客户端 首先&#xff0c;你需要打开Redis的客户端。这通常可以通过在终端或命令提示符中输入redis-cli命令来实现。 2. 连接到Redis服务器…

找出缺失的观测数据

代码实现&#xff1a; 在缺失的 n 个观测数据中&#xff0c;有 y 个观测数据是 x1&#xff0c;其余观测数据都是x int* missingRolls(int *rolls, int rollsSize, int mean, int n, int *returnSize) {int m rollsSize;int sum mean * (n m);int missingSum sum;for (int i…

Java进阶:详解与实战Java Stream API

Java进阶&#xff1a;详解与实战Java Stream API &#x1f31f; Java进阶&#xff1a;详解与实战Java Stream API &#x1f31f;摘要引言一、Java Stream API介绍&#x1f4da;1. 什么是Java Stream API&#xff1f;2. Java Stream API支持的功能3. 使用Java Stream API的优势…

Python-3.12.0文档解读-内置函数id()详细说明+记忆策略+常用场景+巧妙用法+综合技巧

一个认为一切根源都是“自己不够强”的INTJ 个人主页&#xff1a;用哲学编程-CSDN博客专栏&#xff1a;每日一题——举一反三Python编程学习Python内置函数 Python-3.12.0文档解读 目录 详细说明 概述 参数 返回值 特性 实现细节&#xff08;CPython&#xff09; 安全…

F12 网络请求类型:Fetch与XHR的区别

F12 网络请求类型&#xff1a;Fetch与XHR的区别 引言 在Web开发中&#xff0c;浏览器的F12开发者工具是调试网络请求的重要工具。通过F12&#xff0c;我们可以查看各种类型的网络请求&#xff0c;包括fetch和XMLHttpRequest&#xff08;XHR&#xff09;。这两种技术都用于在浏…

Linux——Linux服务管理

服务管理大作业要求&#xff1a; 基本拓扑如下&#xff1a; 按照要求完成基本的系统管理任务&#xff1a; 完成所有系统的主机名、网络配置&#xff1b; 本次作业共需要3台虚拟机&#xff0c;分别作为客户端、综合应用服务器、存储服务器。三台虚拟机操作系统均为CentOS-Stream…

5.2网安学习第五阶段第二周回顾(个人学习记录使用)

本周重点 ①HIDS的基本应用(suricata) ②Suricata的基本应用 ③Suricata的流量检测 ④Suricata的https流量检测 ⑤利用Elastic整合Suricata日志 ⑥利用Wazuh对Suricata主动响应 本周主要内容 ①HIDS的基本应用(suricata) 1、NIDS 1、定义&#xff1a;网络入侵检测系统…

算法简单笔记

本人大二下学期报了中国大学生计算机设计大赛、珠澳计算机设计大赛、区块链软件设计大赛、蓝桥杯......然后一直准备着设计大赛的比赛&#xff0c;根本没空管蓝桥杯&#xff0c;就省考前准备了一星期&#xff0c;感觉是没有希望了&#xff0c;但是很莫名其妙的就拿了蓝桥杯Java…