【五十一】【算法分析与设计】KMP 算法,KMP 算法的作用,KMP 算法流程,KMP 算法证明,KMP 算法代码

news2025/2/7 7:36:53

目录

KMP 算法的作用,解决的问题

KMP 算法的流程

Next 数组

KMP 算法正式过程

KMP 算法的证明过程

Next 数组的求法

Next 数组求法的证明过程

KMP 算法代码

结尾


KMP 算法的作用,解决的问题

1.

首先给你一个字符串 str,然后又给你一个字符串 match,请你再 str 的子串中找,是否存在字符与 match 匹配,如果找到了返回该子串在 str 的开始位置下标,如果没有找到返回 -1。

2.

暴力解法,遍历所有子串需要 O(N*M)的时间复杂度,KMP 算法可以只用 O(N)时间复杂度解决这个问题。

KMP 算法的流程与证明过程

Next 数组

1.

对于 match 数组的每一个元素都有一个对应的数值,存储在 next 数组中。

2.

match[i]对应 next[i]。

3.

next[i]存储的值是,i 位置前面部分的最长公共前后缀的长度。

i 位置前面部分是指 0~i-1 区间。

例如 0~i-1 区间对应字符串为 abcabc。

前缀序列指的是 a,ab,abc,abca,abcab。

后缀序列指的是 c,bc,abc,cabc,bcabc。

公共前后缀长度是指,前后缀序列相同的长度,例如 a 与 c 前后缀序列不相同,ab 与 bc 前后缀序列不相同,abc 与 abc 前后缀长度相同,长度为 3,abca 与 cabc 前后缀序列不相同,abcab 与 bcabc 前后缀序列不相同。

因此最长公共前后缀长度为 3。

4.

人为规定 next[0]=-1,next[1]=0。

KMP 算法正式过程

1.

如果 str[i~X-1]全部与 match[0~Y-1]匹配成功,此时 X 与 Y 匹配失败,Y=next[Y],Y 回退到对应 next 存储的下标位置。

然后新的 Y 下标与 X 继续匹配。

2.

如果 next[Y]==-1,此时说明 Y==0,X++,然后新的 X 下标和 Y 继续匹配。

3.

如果 X 与 Y 匹配成功,X++,Y++,新的 X 与新的 Y 继续匹配。

4.

直到 XY 其中一个越界,如果 X 越界说明 Y 还没有匹配完,后面没有字符了,说明匹配失败,返回 -1。

如果 Y 越界,说明 Y 匹配完了,匹配成功,对应的 str 匹配子串开始下标位置是 X-Y。

KMP 算法的证明过程

1.

如果 str[i~X-1]全部与 match[0~Y-1]匹配成功,此时 X 与 Y 匹配失败,Y=next[Y],Y 回退到对应 next 存储的下标位置。

然后新的 Y 下标与 X 继续匹配。

1.

A 部分和 B 部分相同,C 部分与 B 部分相同,说明 A 部分和 C 部分相同,Y 回退到 next[Y]位置,相当于已经匹配完 AC 部分接下来匹配红色 Y 与 X 位置元素。

2.

为什么 A 部分前面都可以不用考虑?

假设 A 部分前面开始匹配可以匹配成功,那么蓝色框框部分就是匹配成功的子串,上面蓝色部分 C 对应下面蓝色部分 C 是相同的,上面蓝色部分前面一段 C 和绿色框框 D 是相同的,也就是下面绿色 D 和蓝色 C 是相同的,那么 Y 的 next[Y]得到了一个更大的长度,我们 next[Y]最长公共前后缀是 BC 部分,现在推出一个更长的公共前后缀,推出矛盾,说明 A 部分前面都不用考虑。

Next 数组的求法

1.

假设 0~Y-1 的 next 都求完了,cn 是 Y-1 对应的 next 值。

如果 match[cn]==match[Y-1],next[Y]=cn+1。

2.

如果 match[cn]!=match[Y-1],cn=next[cn].

然后新的 cn 继续与 Y-1 进行判断。

3.

如果 next[cn]==-1,说明 cn==0,next[Y]=0。

4.

下一次计算的时候,cn 等于 Y-1 对应的 next 值,初始化。

Next 数组求法的证明过程

1.

首先 next[Y]最大时 A 的长度,当且仅当 match[next[Y-1]]==match[Y]的时候,取得。这是 next[Y]的极限。

不可能大于这个值,如果大于说明最长公共前后缀求错了,推出时矛盾的。

2.

如果 match[cn]!=match[y-1], cn=next[cn].

此时我们在判断紫色位置有没有可能时最长公共前后缀,也就是我们跳过了蓝色区间。也就是我们需要证明蓝色位置不可能是最长公共前后缀开始的位置。

同理,如果蓝色位置有可能成为答案,那么会推出最长公共前后缀求错了,推出矛盾,所以蓝色部分是不可能的区间位置。

3.以此类推....

KMP 算法代码

 
#include<bits/stdc++.h>
using namespace std;
class code01_KMP {
public:
        static int getIndexof(string str, string match) {
                if (str.empty() || match.empty() || str.size() < match.size())
                        return -1;
                int x = 0, y = 0;
                vector<int> next = getNextVector(match);
                while (x < str.size() && y < match.size()) {
                        if (str[x] == str[y]) {//如果相等往后移
                                x++;
                                y++;
                        } else if (next[y] != -1) {//如果不相等,y后退到next[y]位置
                                y = next[y];
                        } else {//如果next[y]==-1,即y==0,x++
                                x++;
                        }
                }//x-a+1=y+1--->a=x-y
                return y == match.size() ? x - y : -1;
        }
        static vector<int> getNextVector(string match) {
                if (match.size() == 1) return { -1 };
                vector<int> next(match.size());
                next[0] = -1;
                next[1] = 0;

                int i = 2;//从下标为2位置开始计算next
                int cn = 0;//i-1位置的next数值
                while (i < next.size()) {
                        if (match[i - 1] == match[cn]) {//如果i-1位置字符与cn相等,cn是某个公共前后缀长度,cn+1表示next[i]
                                next[i++] = ++cn;
                        } else if (next[cn] != -1) {//如果next[cn]!=-1,cn=nect[cn]
                                cn = next[cn];
                        } else {//如果nect[cn]==-1,cn不能等于nect[cn],next[i]==cn==0
                                next[i++] = 0;
                        }

                }

                return next;
        }
        static string getRandomString(int possibilities, int size) {//0-25
                srand(time(NULL));
                //string ans("", rand() % (size + 1));
                string ans("", size);
                for (int i = 0; i < ans.size(); i++) {
                        ans[i] = rand() % (possibilities + 1) + 'a';
                }
                return ans;
        }

};

int main() {
        int possibilities = 5;
        int strSize = 20;
        int matchSize = 5;

        cout << "test begin" << endl;
        string str = code01_KMP::getRandomString(possibilities, strSize);
        string match = code01_KMP::getRandomString(possibilities, matchSize);
        cout << "str:" << str << endl;
        cout << "match:" << match << endl;
        int pos = code01_KMP::getIndexof(str, match);
        if (pos != -1)
                cout << "匹配成功! 开始下标:" << code01_KMP::getIndexof(str, match) << endl;
        else cout << "匹配失败!" << endl;

}

结尾

最后,感谢您阅读我的文章,希望这些内容能够对您有所启发和帮助。如果您有任何问题或想要分享您的观点,请随时在评论区留言。

同时,不要忘记订阅我的博客以获取更多有趣的内容。在未来的文章中,我将继续探讨这个话题的不同方面,为您呈现更多深度和见解。

谢谢您的支持,期待与您在下一篇文章中再次相遇!

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

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

相关文章

酷开系统丨酷开科技打造P9系列智能投影,让智能化更进一步

近些年&#xff0c;随着科技的进步&#xff0c;家用投影仪已经成为家庭娱乐中不可或缺的一部分。尤其对年轻人来说&#xff0c;他们更喜欢在巨幕上看电影、玩游戏或听歌唱歌&#xff0c;投影仪在巨幕上的光影效果确实能带来更好的沉浸感体验&#xff0c;但这也是需要强大的系统…

OpenHarmony实战开发-页面深色模式适配。

介绍 本示例介绍在开发应用以适应深色模式时&#xff0c;对于深色和浅色模式的适配方案&#xff0c;采取了多种策略如下&#xff1a; 1. 固定属性适配&#xff1a;对于部分组件的颜色属性&#xff0c;如背景色或字体颜色&#xff0c;若保持不变&#xff0c;可直接设定固定色值…

零基础也可以学习的医疗设备维修技能

零基础也可以学习的维修技能 解锁工程师的隐藏潜能&#xff01; 您是否曾因维修问题而感到束手无策&#xff1f; 彩虹医疗影像培训课程不仅提供技能&#xff0c; 更能为您提供自信。不再需要依赖他人&#xff0c; 您将成为故障排查的行家。迎接更具挑战性的机会&#xff0…

C#引用外部组件的常用方法

我们在开发程序过程中&#xff0c;时常会使用到第三方组件&#xff0c;比如一些通信、UI组件等。常用的引用方法有下面几种。 01 NuGet引用 NuGet是.NET的一个包管理平台&#xff0c;很多开源组件会通过NuGet进行管理和发布。比如我们常用的S7NetPlus等。 从NuGet中引用组件…

鸿蒙OS开发指导:【应用包签名工具】

编译构建 该工具基于Maven3编译构建&#xff0c;请确认环境已安装配置Maven3环境&#xff0c;并且版本正确 mvn -version下载代码&#xff0c;命令行打开文件目录至developtools_hapsigner/hapsigntool&#xff0c;执行命令进行编译打包 mvn package编译后得到二进制文件&…

(python)远程操作模块-Paramiko

目录 前言 安装 流程 范例 优点 缺点 需要注意的事项 前言 Paramiko 是一个用于 Python 的模块&#xff0c;用于实现 SSH 客户端和服务器。使用 Paramiko&#xff0c;你可以在 Python 中进行 SSH 连接&#xff0c;并执行远程命令、传输文件等操作。 安装 pip install p…

[leetcode] max-area-of-island

. - 力扣&#xff08;LeetCode&#xff09; 给你一个大小为 m x n 的二进制矩阵 grid 。 岛屿 是由一些相邻的 1 (代表土地) 构成的组合&#xff0c;这里的「相邻」要求两个 1 必须在 水平或者竖直的四个方向上 相邻。你可以假设 grid 的四个边缘都被 0&#xff08;代表水&…

模仿SpringSecurity配置文件的写法对mybatisPlus查询方法的改造

使用mybatisPlus查询数据的传统流程是&#xff1a;Autowired mapper对象。new Wrapper 一通乱set Wrapper ,select xxx。但实际开发中&#xff0c;还有很大的改进空间&#xff0c;一是一些脆弱的参数设置有多处&#xff0c;得不到妥善维护&#xff0c;二是代码编写丑陋难看。因…

重生奇迹mu怎么转职

一转&#xff1a;一转的等级是180级&#xff0c;要求就是材料帝王之书收集2本&#xff0c;还需要7万金币就可以直接转职了&#xff0c;帝王之术就是任务了&#xff0c;在任务那里可以看到转职任务&#xff0c;我们只要做了转职任务就可以收集完了&#xff0c;一转分别叫做&…

springboot直接运行 java-jar

一、问题 springboot 为什么能通过java-jar运行&#xff0c;打包的时候也把tomcat打了吗&#xff1f; 二、解答 Spring Boot 应用程序通常打包成可执行的 JAR 文件&#xff0c;并且可以通过 java -jar 命令来运行。这是因为 Spring Boot 在打包时会将应用程序本身和嵌入的 T…

振弦式渗压计的安装与防护:在水工建筑物中的关键应用

振弦式渗压计&#xff0c;作为一种高效的孔隙水压力或液体液位测量工具&#xff0c;广泛应用于水工建筑物、基岩内、测压管、钻孔、堤坝、管道和压力容器内。其安装和防护工作至关重要&#xff0c;直接关系到测量数据的准确性和仪器的使用寿命。本文将重点探讨振弦式渗压计在填…

武汉星起航引领跨境电商新浪潮,与亚马逊携手共拓全球市场

在全球贸易日益繁荣的当下&#xff0c;跨境电商行业正迎来前所未有的发展机遇。武汉星起航电子商务有限公司&#xff0c;作为跨境电商领域的佼佼者&#xff0c;凭借其前瞻性的战略布局和强大的运营能力&#xff0c;与亚马逊跨境电商平台紧密合作&#xff0c;共同推动全球贸易的…

【C语言】<动态内存管理>我的C语言终末章

&#xff1c;动态内存管理&#xff1e; 1. 为什么要有动态内存分配2. malloc和free2.1 malloc2.2 free 3. calloc和realloc3.1 calloc3.2 realloc 4.常见的动态内存错误4.1 对NULL指针的解引用操作4.2 对动态开辟空间的越界访问4.3 对非动态开辟内存使用free释放4.4 使用free释…

为什么公司在访问控制中转向人工智能

门禁系统通过帮助维护安全和保护资产来实现基本功能。另一方面&#xff0c;传统的访问控制方法有许多缺点&#xff0c;可能不如理想情况下有效。人工智能 &#xff08;AI&#xff09; 正成为企业改进访问控制措施的越来越受欢迎的选择&#xff0c;作为弥补上述缺陷的一种手段。…

区块链安全-----接口测试-Postman

Postman是一款支持http协议的接口调试与测试工具&#xff0c;其主要特点就是功能强大&#xff0c;使用简单且易 用性好 。无论是开发人员进行接口调试&#xff0c;还是测试人员做接口测试&#xff0c;Postman都是我们的首选工具 之一 。 更早的接入测试&#xff0c;更早的发现问…

Matroska解封装原理与实践

本期作者 背景 Matroska是一种开放标准、功能强大的多媒体封装格式&#xff0c;可容纳多种不同类型的视频、音频及字幕流&#xff0c;其常见的文件扩展名为.mkv、.mka等。与应用广泛的MP4相比&#xff0c;Matroska更加灵活开放&#xff0c;可以同时容纳多个字幕&#xff0c;甚至…

B端:导航条长得不都一样吗?错了,这里看过来就懂了。

B端导航条看似都一样&#xff0c;大差不差&#xff0c;仔细看一下&#xff0c;其实各有各的不同&#xff0c;这里方向了十多个&#xff0c;大家仔细看细节。

使用TomCat在idea写一个可以实现分页查询的前后端学生项目04.12

使用TomCat在idea写一个前后端学生项目04.12项目包-CSDN博客 在前端界面需要引入的插件&#xff1a; 在该网站下载需要的插件 Maven Repository: Search/Browse/Explore (mvnrepository.com)https://mvnrepository.com/ 分页查询&#xff1a; 在前端jsp页面使用c:forEach c:…

LeetCode55题:跳跃游戏(原创)

【题目描述】 给你一个非负整数数组 nums &#xff0c;你最初位于数组的 第一个下标 。数组中的每个元素代表你在该位置可以跳跃的最大长度。 判断你是否能够到达最后一个下标&#xff0c;如果可以&#xff0c;返回 true &#xff1b;否则&#xff0c;返回 false 。 示例 1&am…

四.音视频编辑-音频混合-概述

引言 当我们在前两篇博客中成功地构建了一个媒体组合&#xff0c;并且略过了音频部分时&#xff0c;我们意识到了我们需要对这个项目进行更详细的探讨。在本篇博客中&#xff0c;我们将会展示如何创建一个包含视频轨道、配音音频轨道以及背景音频轨道的完整媒体组合。更进一步…