BF算法,KMP算法

前言:今天我们来学习两种算法,BF算法和KMP算法。相信会让许多小伙伴们打开新世界的大门。

1 BF算法

实践是检验真理的唯一标准。举一个例子说明BF算法。现在我们要在一个主串中找子串的位置。那我们该如何解决这个问题呢?最简单的办法自然是使用C语言中的库函数strstr。

#include<stdio.h>
#include<string.h>
int main()
{char str1[20] = "abbbcdef";char str2[20] = "bbc";char* ret = strstr(str1, str2);char* ps = strncpy(ret, "hello", 5);printf("%s\n", str1);return 0;
}

但现在我们不使用C语言中的库函数strstr,是否有办法可以解决呢?当然是有的。

#include<stdio.h>
#include<assert.h>
#include<string.h>
char* BF(char* str1, char* str2)
{assert(str1 != NULL && str2 != NULL);char* s1 = str1;//遍历主串char* s2 = str2;//遍历子串char* cur = str1;//记录可能开始匹配的位置while (*cur){//完成一次匹配s1 = cur;s2 = str2;while (*s1 && *s2 && *s1 == *s2){s1++;s2++;}if (*s2 == '\0'){return cur;}cur++;}return NULL;
}
int main()
{char str1[20] = "abbbcdef";char str2[20] = "bbc";char* ret = BF(str1, str2);char* ps = strncpy(ret, "world", 5);printf("%s\n", str1);
}

画图分析

*s1=a,*s2=b。此时 *s1 != *s2,说明从cur这个位置匹配失败,那么下一次就要从cur++的位置开始匹配,同时将s1的位置更改为新的cur

在这里插入图片描述


*s1=b,*s2=b。此时*s1==*s2,说明从当前cur的位置是有可能匹配成功的。那么就执行s1++,s2++的操作,比较下一对字符的内容

在这里插入图片描述


在这里插入图片描述


*s1=b,*s2=c。此时*s1!=*s2,说明从cur的位置匹配失败,进一步更新cur的位置,同时将s1的位置更新为新的cur的位置,s2回到起始位置。重新进行下一次的匹配

在这里插入图片描述


更新之后新的cur和s1的位置以及s2的位置

在这里插入图片描述


这里省略了相同的步骤,直接演示最后的结果。

在这里插入图片描述

这就是所谓的BF算法。大家是否理解了呢?接下来就让我们一起来学习更加高深莫测的KMP算法。大家做好准备哦。

2 KMP算法

依然是在主串中找寻子串的位置。这一次使用KMP算法实现。

什么是KMP算法呢?

KMP算法是一种改进的字符串匹配算法KMP算法的核心思想是利用主串与模式串(子串)匹配失败后的信息,尽量减少模式串(子串)与主串匹配的次数以达到快速匹配的目的。具体实现是通过一个next数组实现,数组本身包含了子串的局部匹配信息。KMP算法的时间复杂度O(m+n)

KMP算法与BF算法的区别是:主串的i并不会回退,子串的j不一定回退到0位置

画图分析

从当前 i 的位置开始匹配,匹配成功就执行 i++,j++的操作,接着匹配下一对字符的内容

在这里插入图片描述


这里省略了相同的步骤,直接演示最后的结果。此时匹配失败,i不会进行回退,j回退到一个随机的位置

在这里插入图片描述

该回退到哪里呢?这是一个值得深思的问题。在这个位置匹配失败就意味着 i 前面和 j 前面有一部分是相同的。那我们来研究一下 j 到底该回退到哪里呢?

在这里插入图片描述

假设1与3的内容相同,2与3的内容相同。那么1与2的内容就相同。如果此时下标 i 与下标 j 的内容不匹配,j 应该回退到哪里去呢?j 应该回退到子串中下标为2的位置去。为什么呢?还记得KMP算法的核心思想吗。需要尽量减少模式串与主串匹配的次数以达到快速匹配的目的1与3的内容相同,就没有必要再进行重复的匹配,因此 j 应该回退到子串中下标为2的位置。如果依然匹配失败,就继续回退

那新的问题又来了,我们要怎么得到回退的位置呢?根据上面的图分析,假设子串叫做p,如果p[0]~p[1]之间的内容等于p[3]~p[4]之间的内容,我们会发现相等部分的长度为2,刚好是 j 要回退的位置。那不就出来了。next数组的作用就是保存子串中某个位置匹配失败后,要回退的位置

KMP的精髓就是next数组,也就是用next[j]=k来表示,不同的j表示不同的k值,这个k就是你将来要移动的j要移动的位置

k值的求法:

. 找到匹配成功部分的两个相等的真子串(不包含本身),一个以下标0的字符开始,另一个以下标为 j-1 的字符结尾。这两个真子串的长度就是k值

. 不管什么数据,next[0]=-1,next[1]=0

接下来的问题就是已知next[j-1]=k,如何求next[j]=?

在这里插入图片描述


在这里插入图片描述

next数组的特点:相邻的k值如果是增加的,一定是逐步加1的过程

KMP算法的实现

#include<stdio.h>
#include<assert.h>
#include<string.h>
#include<stdlib.h>
//str代表主串
//sub代表子串
//pos代表主串开始匹配的位置
void GetNext(int* next, char* sub, int LenSub)
{assert(next != NULL && sub != NULL && LenSub);next[0] = -1;next[1] = 0;int i = 2;int k = 0;//保存前一项的k值while (i < LenSub){if (-1 == k || sub[i - 1] == sub[k]){next[i] = k + 1;i++;k++;}else{k = next[k];//有可能回退到-1,子串进行访问时会出现越界访问}}
}
int KMP(char* str, char* sub, int pos)
{assert(str != NULL && sub != NULL);int LenStr = (int)strlen(str);int LenSub = (int)strlen(sub);if (0 == LenStr || 0 == LenSub){return -1;}if (pos < 0 || pos >= LenStr){return -1;}int* next = (int*)malloc(sizeof(int) * LenSub);if (NULL == next){perror("空间开辟失败的原因是");return -1;}GetNext(next, sub, LenSub);int i = pos;//遍历主串int j = 0;//遍历子串while (i < LenStr && j < LenSub){if (-1 == j || str[i] == sub[j]){i++;j++;}else{j = next[j];//有可能回退到-1,子串进行访问时会出现越界访问}}if (j >= LenSub){return i - j;}else{return -1;}free(next);next = NULL;
}
int main()
{printf("%d\n", KMP("abbbcdefg", "bbc", 0));//2printf("%d\n", KMP("abbcdef", "ab", 0));//0printf("%d\n", KMP("abccdef", "bcd", 0));//-1printf("%d\n", KMP("abbcdabcdef", "abc", 0));//5printf("%d\n", KMP("abbccddef", "abcde", 0));//-1printf("%d\n", KMP("abcddef", "ab", 0));//0return 0;
}

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

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

相关文章

Repeat方法:取模运算教材与Unity控制台输出数值不同的原因

学习该知识点的参考教材&#xff1a;Unity API解析/陈宏泉编著.——北京&#xff1a;人民邮电出版社&#xff0c;2014.9 编辑脚本的环境&#xff1a;Visual Studio 2022 在学习该本教材的第五章Mathf类的内容&#xff0c;通过跟随教材上的代码了解不同UnityAPI的具体用法时&a…

【机器学习】线性回归与逻辑回归的极致解析:从数学理论到实战案例

文章目录 1. 引言Python 代码示例 2. 线性回归2.1 线性回归的基本概念线性回归的定义数学表达式及模型假设 2.2 线性回归的工作原理最小二乘法&#xff08;Ordinary Least Squares, OLS&#xff09;梯度下降法在线性回归中的应用多元线性回归与一元线性回归的区别与联系 2.3 线…

什么是AR、VR、MR、XR?

时代背景 近年来随着计算机图形学、显示技术等的发展&#xff0c;视觉虚拟化技术得到了广泛的发展&#xff0c;并且越来越普及化&#xff0c;慢慢的也走入人们的视野。目前市场上视觉虚拟化技术的主流分为这几种 VR、AR、MR、XR。这几项技术并不是最近才出现的&#xff0c;VR的…

机器学习笔记 第十二章计算学习理论

12.1 基础知识 计算学习理论就是关于机器学习的理论基础&#xff0c;其作用就是分析学习任务的困难实质&#xff0c;通过分析结果来知道算法设计&#xff0c;并为学习算法提供理论保证。 给定样例集&#xff0c;&#xff0c;假设为二分类问题&#xff0c;一般。假定中的所有样…

GoMail发送邮件的性能优化策略有哪些方法?

GoMail发送邮件如何配置服务器&#xff1f;GoMail发信功能如何&#xff1f; GoMail是一款广受欢迎的Go语言邮件发送库&#xff0c;具备高效、易用等优点&#xff0c;但在高并发场景下&#xff0c;GoMail发送邮件的性能优化显得尤为重要。AokSend将探讨几种有效的GoMail发送邮件…

PDF Shaper Ultimate v14.4 中文授权版

如今对PDF处理的软件很多都是只是单一的功能。PDF Shaper给你完全不同的体验&#xff0c;因为PDF Shaper是一款PDF工具集合的软件。有了PDF Shaper&#xff0c;你以后再也不用下载其他处理PDF的软件了。PDF Shaper的功能有&#xff1a;合并&#xff0c;分割&#xff0c;加密和解…

贪吃蛇(C语言详解)

贪吃蛇游戏运行画面-CSDN直播 目录 贪吃蛇游戏运行画面-CSDN直播 1. 实验目标 2. Win32 API介绍 2.1 Win32 API 2.2 控制台程序&#xff08;Console&#xff09; 2.3 控制台屏幕上的坐标COORD 2.4 GetStdHandle 2.5 GetConsoleCursorlnfo 2.5.1 CONSOLE_CURSOR_INFO …

ant design pro access.ts 是如何控制多角色的权限的

ant design pro 如何去保存颜色ant design pro v6 如何做好角色管理ant design 的 tree 如何作为角色中的权限选择之一ant design 的 tree 如何作为角色中的权限选择之二 看上面的图片&#xff0c;在前端中如何控制这些权限&#xff0c;比如控制按钮的显示&#xff0c;还有菜单…

【Linux操作系统】进程控制

目录 一、进程创建1.1 认识fork1.2 写时拷贝 二、进程终止2.1 进程退出2.2 函数退出2.3 exit 三、进程等待四、程序替换 一、进程创建 1.1 认识fork fork函数是系统调用接口&#xff0c;用来创建子进程的 根据进程的pid&#xff0c;可以看出父进程fork后分为父进程和子进程…

找到你的任务管理伙伴:待办事项软件终极指南

国内外主流的10款待办事项管理软件对比&#xff1a;PingCode、WorktileTodoist、TickTick、Teambition、 Microsoft To Do、. Asana、Tower、番茄ToDo、飞书。 在面对日益复杂的工作和个人任务时&#xff0c;找到一款能够有效帮助你管理日常待办事项的软件&#xff0c;变得越来…

[RCTF2015]EasySQL1

打开题目 点进去看看 注册个admin账户&#xff0c;登陆进去 一个个点开看&#xff0c;没发现flag 我们也可以由此得出结论&#xff0c;页面存在二次注入的漏洞&#xff0c;并可以大胆猜测修改密码的源代码 resoponse为invalid string的关键字是被过滤的关键字&#xff0c;Le…

blender内置树木的UV

之前听说用这个内置插件可以创建树木 我这边的默认配置出来的树木长这样&#xff0c;不得不想一下&#xff0c;他的uv怎么展&#xff0c;看起来好多树 我尝试看了一眼默认的UV 结果如下 好像每个树枝都已经是平铺的样子了&#xff0c;那么如果需要改的话&#xff0c;就根据…

大模型预训练与微调之间的关系

1. 引言 大语言模型的兴起与训练范式 在过去的十年中&#xff0c;随着计算能力和数据规模的显著提升&#xff0c;大语言模型&#xff08;Large Language Models, LLMs&#xff09;在自然语言处理&#xff08;Natural Language Processing, NLP&#xff09;领域掀起了一场革命…

基于Python的火车票售票系统/基于django的火车购票系统

摘 要 随着信息技术和网络技术的飞速发展&#xff0c;人类已进入全新信息化时代&#xff0c;传统管理技术已无法高效&#xff0c;便捷地管理信息。为了迎合时代需求&#xff0c;优化管理效率&#xff0c;各种各样的管理系统应运而生&#xff0c;各行各业相继进入信息管理时代&…

stripe Element 如何使用

这里要准备好几个东西&#xff1a; 一个支付成功过后的回调 还有一个下单的接口 一旦进入这个下单界面&#xff0c;就要去调下单的接口的&#xff0c;用 post, 这个 接口你自己写&#xff0c;可以写在后端中&#xff0c;也可以放到 nextjs 的 api 中。 首先说的是这个下单…

算法【Java】—— 双指针算法

双指针算法 常见的双指针有对撞指针&#xff0c;快慢指针以及前后指针&#xff08;这个前后指针是指两个指针都是从从一个方向出发&#xff0c;去往另一个方法&#xff0c;也可以认为是小学学习过的两车并行&#xff0c;我也会叫做同向指针&#xff09;&#xff0c;在前后指针…

vscode中使用官方推荐的编程字体Cascadia Code字体

字体样式 > 和 有特殊效果 很多字体都支持使用连字&#xff0c;Cascadia Code 、Jetbrains Mono 、Fira Code 等 安装Cascadia Code 下载完成后解压安装 选中右键安装&#xff0c;static文件里也一样安装 VS Code 中配置设置字体和连字设置 Cascadia Code, Consolas, Couri…

计算机的错误计算(六十七)

摘要 计算机的错误计算&#xff08;五十六&#xff09;与&#xff08;六十六&#xff09;分别探讨了大数与 附近数的正切函数值的错误计算。本节讨论第三种类型数值&#xff1a; 附近数 的正切函数的计算精度问题。 例1. 已知 计算 先用 Go语言计算&#xff1a; packag…

STL介绍以及string类

什么是STL 是C标准库的重要组成部分&#xff0c;不仅是一个可复用的组件库&#xff0c;而且是一个包罗数据结构与算法的软件框架。 STL的六大组件 为什么要学习string类 C语言中的字符串 C语言中&#xff0c;字符串是以\0结尾的一些字符的集合&#xff0c;为了操作方便&am…

模具监视器的技术参数有哪些

模具监视器的技术参数涵盖了多个方面&#xff0c;这些参数对于确保模具监视器的性能、稳定性和检测精度至关重要。以下是一些主要的技术参数&#xff1a; 一、显示器参数 屏幕尺寸&#xff1a;常见的模具监视器显示器尺寸为12.5英寸至13.5英寸&#xff0c;具体尺寸可能因不同…