算法基础(一):串匹配问题(BF,KMP算法)-天天看热讯
好家伙,学算法,
【资料图】
这篇看完,如果没有学会KMP算法,麻烦给我点踩
希望你能拿起纸和笔,一边阅读一边思考,看完这篇文章大概需要(20分钟的时间)
我们学这个算法是为了解决串匹配的问题
那什么是串匹配?
举个例子:
我要在"彭于晏吴彦祖"这段字符串中找到"吴彦祖"字符串
这就是串匹配
这两个算法太抽象了,我们直接做题吧
题目如下:
在A=“abcaaabaabaaac”中查找子串B=“aabaaa”,写出采用BF算法和KMP算法进行串匹配的全过程
1.BF(Brute Force,暴力)算法暴力算法,我们从第一位开始进行匹配
1.1.若匹配成功,则匹配字符串"B"的下一位,
1.2.若匹配失败,则字符串"B"整体向右移动
直到匹配成功
匹配流程图:
第一次匹配:
可以看见在进行第二个字符"a"的匹配时,匹配失败,字符串"B"整体右移
第二次匹配:
第三次匹配:(不想画图..)
第四次匹配:
第五次匹配:
第六次匹配(不想画图....算了还是画吧):
第七次匹配:
直到第八次:
直到全部字符串B全部匹配成功(又或者出现无法匹配的情况)
看看代码实现:
#include#include int find_substring(char *A, char *B) { int m = strlen(A); // A串长度 int n = strlen(B); // B串长度 int i, j; for (i = 0; i <= m - n; i++) { // i表示在A串中从第i开始查找子串B for (j = 0; j < n; j++) { // j表示在B串中与A串中的字符逐个比较 if (A[i+j] != B[j]) // 不匹配则退出j循环 break; } if (j == n) // 如果B串全部匹配,则返回A串中子串B第一次出现的位置 return i; } return -1; // 如果没有匹配成功,则返回-1}int main() { char A[] = "abcaaabaabaaac"; char B[] = "aabaaa"; int index = find_substring(A, B); if (index >= 0) printf("子串B在A中第一次出现的位置是:%d\n", index); else printf("A中没有子串B\n"); return 0;}
嗯,看上去毫无技术含量
核心算法部分两个for循环写完了
接下来进入本篇的主要内容
2.KMP(Knuth Morris Pratt算法)这个算法是以人名命名的,那么,做好心理准备,这必然会有一定难度
2.1.我想偷懒(算法优化)在前面BF算法的推演中,相信聪明的你一定察觉到了某些步骤看上去很多余
2.1.1.情况一
回到前面的推演
如果我们用"人"的思维去进行字符串匹配,会发现
第六次匹配和第七次匹配完全是可以省略的,
我直接跳到"那个看上去正确"的位置
这么做是对的,可是这没有确切依据,凭借的是"直觉"
2.2.2.情况二
你也可能会有这样的想法:
我把已经配对过的字符全部跳过
"将匹配过的字符都跳过 "
于是,直接从第五次匹配跳到第十次匹配
直接跳到第十次匹配:
虽然达到了偷懒的目的,但错过了正确的答案
但你同样需要记住这个错误的情况
这有助于后续的理解
2.2.路标(部分匹配值表)在前面,你知道,你不想达成情况二,你想要达成情况一
这时,你需要有个路标给你指示
(这或许是个不太好的比喻,
假设你现在吃坏肚子了,在某个大型的广场找厕所,你会怎么办?
我会抬头去找每个分岔路口的标识符,
你看见标识符了,在那边..)
这时候,我把我的字符串"B"的路标给你(后面会解释路标怎么来的)
部分匹配值表:然后这个表该怎么用呢?
当匹配失败后,字符串"B"的移动位数P等于已匹配字符串数减去对应匹配值
比如说在第五次匹配中,
事实上,它移动的位数P = 已匹配字符串数 -部分匹配值表对应匹配值
也就是 P = 5 - 2 = 3
而我们在推演中,也确实移动了3位
2.3.路标(部分匹配值表)的计算这时候你开始疑问了?哥们,你这表怎么来的?
就两个字"规律"
看看这字符串吧"aabaaa"我们试图从中找出{已匹配字符串数}与{字符串B}的联系
"前缀"和"后缀"。 (1)"前缀"指除了最后一个字符以外,一个字符串的全部头部组合;
(2)"后缀"指除了第一个字符以外,一个字符串的全部尾部组合
"前缀"和"后缀"的最长的共有元素的长度
当{已匹配字符串数}为1,"a"的前缀为空, 后缀为空 共有元素长度为0
当{已匹配字符串数}为2,"aa"的前缀为[a], 后缀为[a], 共有元素长度为1
当{已匹配字符串数}为3,"aab"的前缀为[a,aa], 后缀为[b,ab], 共有元素长度为0
当{已匹配字符串数}为4,"aaba"的前缀为[a,aa,aab], 后缀为[a,ba,aba], 共有元素长度为1
当{已匹配字符串数}为5,"aabaa"的前缀为[a,aa,aab,aaba], 后缀为[a,aa,baa,abaa], 共有元素长度为2
当{已匹配字符串数}为6,"aabaaa"的前缀为[a,aa,aab,aaba,aabaa],后缀为[a,aa,aaa,baaa,abaaa],共有元素长度为2,但是这已经无所谓,当匹配完成,部分匹配值表不再被需要
此时我们把共有元素填到表中,就得到了我们的"路标"表,当然了,他真正的名字是"部分匹配值表"
这时你会有两个疑问:
1.子串B=“aabaaa”的部分匹配值表为什么与A=“abcaaabaabaaac”是否有关?为什么?答:无关
在KMP算法中计算子串B的部分匹配表时,我们只需要关注B本身,而不需要考虑B要在哪个字符串中进行匹配。
具体而言,部分匹配值的计算是通过B串本身的前缀和后缀来确定的,并不依赖于任何与B进行匹配的字符串的特定属性。
因此,子串B的部分匹配值表与A字符串中的字符内容和长度无关。可以在不考虑主串A的情况下,完全独立地计算出B的部分匹配值表。
2.为什么要如此麻烦地使用KMP算法,而不是使用更为方便地BF算法?来吧,算法永远离不开的好朋友,时间复杂度O()
2.1.现在假设字符串A,B的长度分别为n,m
(1)BF算法
BF算法如此暴力,他的时间复杂度自然也很暴力,
不考虑最好最坏,平均的情况:在文本串和模式串的匹配字符数量较为相等的情况下,BF算法的时间复杂度为O(nm/2),也就是O(nm)。
(2)KMP算法
考虑最好最坏情况
最好的情况:当文本串和模式串的匹配字符非常少时,KMP算法的时间复杂度为O(n),其中n是文本串的长度。
最坏的情况:当文本串和模式串匹配字符非常多且不匹配时,KMP算法的时间复杂度为O(n+m),其中n是文本串的长度,m是模式串的长度。
平均的情况:在文本串和模式串的匹配字符数量比较接近的情况下,KMP算法的时间复杂度为O(n+m)。
你看见了吗? nm和n+m,直接少了一个数量级,以人名命名的算法还是有点东西的
所以,结论:因为KMP算法的时间复杂度远低于BF算法,KMP算法更高效
好了你已经掌握了KMP算法思想的百分之七十了,其中最核心的部分匹配值表你已经掌握了
接下来的内容,是关于代码实现的
2.4.next()数组这是便于代码实现和使用的{部分匹配值表}版本,它本质上还是部分匹配值表
既然是不同版本,那么它一定会遵循某些规则
部分匹配表为[ 0 1 0 1 2 0 ],则对应的next数组为[ -1 0 1 0 1 2]。
具体操作:整体右移,然后首位赋值为-1
(1)第一步:整体右移
(2)第二步:首位赋值-1,
在KMP算法中,next数组的第一个元素next[0]的值必须为-1。
这是因为在算法中需要将待匹配串移动1个位置,如果next[0]的值为0,则下一次匹配就会跳过第一个字符,进入一个错误的状态。
而将next[0]设置为-1,则下一次匹配将从第一个字符开始,以正确的方式继续匹配。
又或者我们以另一种方式去理解:
第二种理解方式:
我们依旧使用那个方法去计算字符串匹配失败后移动的位数,移动位数P = 已配对字符串数 - next[i]
所以 如果一个字符都没配对,也就是匹配的字符串为0那么 移动位数 P =已配对字符串数 - next[0] = 0 - (-1) = 1
如果配对了5个字符,那么 移动位数 P =已配对字符串数 - next[5] = 5 - 2 = 3
如果还是理解不了,试着自己做题,或者上机试试
例题:A="aabbaabbaaabaac" B="aaabaa" 写出他的部分匹配表和next[]数组,并写出它匹配的过程
2.5.代码实现KMP算法#include#include #include void getNext(char* p, int* next, int n);/* 在A中查找子串B的位置 */int kmp_search(char* A, int n, char* B, int m){ int i = 0, j = 0; int *next = (int*)malloc(sizeof(int) * m); // 申请next数组 getNext(B, next, m); // 计算B串的next数组 while (i < n && j < m) { // 从头到尾扫描A串和B串 if (j == -1 || A[i] == B[j]) { // 匹配成功或者失配 i++; j++; } else { j = next[j]; // 失配时根据next数组调整j的位置 } } free(next); // 释放申请的空间 if (j == m) { // 匹配成功 return i - m; } else { // 匹配失败 return -1; }}/* 计算模式串的next数组 */void getNext(char* p, int* next, int n){ int j = 0, k = -1; next[0] = -1; // next数组的第一个值为-1 while (j < n - 1) { // 计算next数组 if (k == -1 || p[j] == p[k]) { // 相等情况 j++; k++; next[j] = k; } else { k = next[k]; // 不相等情况,回溯(k指针回溯) } }}int main(){ char A[] = "abcaaabaabaaac"; char B[] = "aabaaa"; int lenA = strlen(A); // 计算A的长度 int lenB = strlen(B); // 计算B的长度 int pos = kmp_search(A, lenA, B, lenB); // 在A中查找B的位置 if (pos == -1) { printf("在A中没找到B!\n"); } else { printf("在A中找到B, 位置为 %d\n", pos); } return 0;}
标签:
推荐文章
- 算法基础(一):串匹配问题(BF,KMP算法)-天天看热讯
- 找病灶 开药方 医疾病 鄂州社会治理新路:“半月谈”-环球看热讯
- 环球短讯!惠城环保(300779.SZ):广东石化建设的高硫石油焦制氢气项目是全国首套装置
- 250太子摩托车油耗(250太子摩托车)
- 小麦收割完成率98.41% 镇江夏收工作基本结束
- 海南四部门联学联建共促共进 推动主题教育走深走实 天天视点
- 德媒:德国人每天喝3.4杯咖啡,“咖啡比朋友重要”_环球观热点
- 热敏打印机打不出字的原因及解决方法_热敏打印机打不出字
- 智己LS7入门版6月12日发布!车电分离或售22.98万 微动态
- 环球热点评!江西省赣州市2023-06-06 21:31发布暴雨橙色预警
- 动态:今日期货市场要闻速递(6月9日)
- 全球最资讯丨【第六届甘肃·祁连山论坛】打造“四强”行动核心引擎——第六届“甘肃·祁连山论坛”分论坛成功举行
- 璞泰来(603659):6月8日北向资金增持156.59万股-天天通讯
- 全国中老年羽毛球邀请赛在湖北十堰开赛 天天报道
- 尸约_尸茧
- 【环球时快讯】多位大咖分享工业设计“干货”
- 东箭科技:接受中泰证券调研
- 【汽车人◆葳漪专栏】国六b才来?又提国七?-天天热议
- 全球热推荐:可重复使用,最多可坐7人!新一代载人飞船什么样?
- 天天速读:大东南(002263):6月8日北向资金增持31.48万股
- 全球新动态:锋尚文化:目前公司正在积极筹备对接周杰伦数实融合的相关业务和产品
- 世界热消息:唐德影视:股东吴宏亮计划减持公司股份不超过2.04%
- 时讯:我爱我家:对于新房业务总体偏谨慎,将继续聚焦存量房和租赁市场
- 随着天空变成红色 《暗黑4》的宣发变得不详
- 【四川文产企“话”】域上和美:继《只此青绿》后,将在雅安打造《熊猫归来》_前沿资讯
- 每日短讯:“AI诈骗潮”真的要来了?
- 淮北市十四届人大二次会议政府报告(关于淮北市十四届人大二次会议政府报告介绍)_环球即时
- 海外网友热议WBG击败LNG:LNG被高估了!中野2人一直送,打得很差_焦点资讯
- 宴会服务方式_男士生日礼物送啥好50岁 环球热讯
- GPLP投融资:芯享科技获1.5亿元 蓝固新能源获1亿元|热门
- 拧紧防溺水“安全阀” 织牢校园安全“防护网” 天天快看点
- 上交所邱勇:将健全制度体系,构建科技创新良好生态-环球今日讯
- 俄高官:乌克兰曾迫于美国压力放弃与俄签署和平协议
- 焦点报道:总结vue3 的一些知识点:MySQL 连接的使用
- 虎年霸气古诗有哪些 虎年春节古诗有哪些?
- 一汽奔腾NAT续航达成率97.85%,青岛网约车司机都在夸|全球观速讯
- 至于高考迟到几分钟近不近人情的事,本人这里有个极端的例子|世界热文
- 唐山公积金租房提取条件
- 龙芯中科与甘肃庆阳市达成战略合作
- 热消息:直面行业痛点,银河L7通过4项整车级电池安全测试
- 古代朱姓名人_朱姓名人
- 苏州市相城区人大常委会党组成员、副主任李彩男接受纪律审查和监察调查|每日热点
- 全球观察:宁夏文化和旅游产业投融资大会在银川举行
- 当前短讯!洋葱能降血压吗?
- 创新融生态加速双转型 2023年施耐德电气创新峰会盛大开幕|世界快报
- 世界热门:唏嘘!淮安一男子如此庆祝孩子入党……
- 中煤能源: 公司暂未向港交所申请参与“港币—人民币双柜台模式” 快讯
- 小学“初体验” 洪山区实验幼儿园香趣园走进小学|报资讯
- 怎么关闭情侣空间qq号(怎么关闭情侣空间)|百事通
- 全球消息!中国农业银行董事长谷澍:聚焦创新链和产业链深度融合 完善科创金融专属服务体系
- 【天天速看料】多地对接受辅助生殖家庭发放补贴 福建一地“试管婴儿”补助2万
- 环球微动态丨6月8日日播时尚涨停分析:锂电池,纺织服装,智能制造概念热股
- 全球速看:华银电力拟投资建设大唐华银益阳市赫山区兰溪渔光互补光伏发电项目
- 新轮胎出厂多长时间就不能购买了呢_新轮胎出厂多长时间就不能购买了
最新资讯
- 汉阴县人民医院_关于汉阴县人民医院简述_环球视点
- 全球通讯!潘功胜:我国外汇市场将有条件保持较为平稳的运行状态
- 世界滚动:换单位了社保怎么转移到新单位(换单位了社保怎么转移)
- 世界热门:小心益生菌市场的这些“套路”
- 当前信息:调剂院校就业率排名靠后 考研要怎样调剂?如何调剂更合适?
- 世界资讯:118家公司拟调入新三板创新层 72家符合北交所上市财务条件
- 教育部:教育考试机构要为残疾考生提供合理便利
- 天天快资讯丨队魂助阵!韦德现身美航球馆 与巴特勒拥抱耳语&面授机宜
- 环球观热点:洪都拉斯总统将访华 中国外交部介绍此访安排及期待
- 十本部落战最强阵型(十本部落战稳三星打法)-每日快报
- 【时快讯】收评: A股今天差一点自己放弃了自己!大幅缩量十字星,地量见底?还是下跌中继?对于接下来的走势,老手已了然于胸。
- 世界球精选!向总书记报告丨绘一幅水清岸绿的“画卷”
- 梅园好时光
- 长春启璞科技信息咨询有限公司入围《信用中国》栏目
- 中国旅行者出境游搜索热度暴涨近六倍-天天新资讯
- 一般纳税人房屋出租简易征收税率(房屋租赁税率11 简易征收5)-全球百事通
- 平度聚力师资培养提升教育“软实力” 全球快播
- 每日资讯:长治经开区13家企业上榜省级创新名单
- 焦点日报:赛场内外大坂直美,她已怀孕,男友是美国说唱歌手
- 2023年高考全国甲卷作文命题思路与解析|天天观速讯
- Reddit现在原生支持图像库 这是它的工作方式
- 江苏出台14条措施推动外贸稳规模优结构-速递
- 每日简讯:广东自贸试验区累计办理FT账户资金业务超2万亿元
- 世界动态:大摩:看好国泰向政府派发股息 潜在复派普通股股息 评级增持
- 翻译英文翻译中文_昔有二翁同邑而居翻译和注释
- 王导:早盘1965空获利,1970空单进场 当前时讯
- 最新消息:23安徽债58今日发布发行公告
- 【热闻】红宝石集团5.22亿元竞得珠海鹤洲新区1宗宅地
- 华安证券:苹果开拓性MR新品发布 持续催化传媒行业内容生态型企业向好
- 借新能源东风深入重卡市场,宇通重卡全系新品上市|天天播资讯
- 尖山街居家养老中心启用 天津再添一家养老服务综合体
- 美好家园绘画作品又简单又漂亮 美好家园绘画作品_天天百事通
- 春秋前是哪个朝代_春秋之前什么朝代_热消息
- 环球热点评!逾期多长时间上征信 逾期以后怎么补救
- 兆龙互连06月07日大涨,股价创历史新高
- 优博讯:公司作为长期专注于AIDC领域的企业,一直致力于为行业客户提供AIDC全栈式解决方案_环球头条
- “地球褶皱”里的山海情
- 江苏出台14条措施推动外贸稳规模优结构 天天头条
- 在趣头条里将红包提现到微信的操作过程
- 不懂就要问这篇课文告诉我们什么道理_滚动
- 天天快讯:3辆全新特斯拉超跑竟被遗弃中国码头13年!原车主身份不简单
- 广东煲汤的做法大全_送给爱喝汤的你
- 实时:长城的介绍资料500字_长城的介绍
- 海底地震一定会引发海啸吗_地震引发海啸时应该怎么办 视点
- 体验35万最值得买的家用SUV 蔚来全新ES6只有一个缺点?_天天短讯
- 不挂p档会溜车吗_溜车风险未挂入p档什么意思
- 直击高考第一天!宝山3000余名学子向梦想进发 全球新消息
- 瘫痪的姚晨和60岁的闫妮:她们怎么变成这样了
- 光大证券收警示函 持续督导纳芯微帝科股份存4宗违规
- 北向资金净买入25.1亿元 交易活跃度下降





