KMP字符串对比算法及next数组计算
(注:该贴主要运用python实现该算法)
先谈谈KMP算法吧。KMP算法的全称是Knuth-Morris-Pratt 算法,它是用来进行字符串查找,即在某个主字符串里面找到某个特定子字符串。但是好像这个问题也可以直接暴力查找来完成啊,可是暴力查找的的缺点是不可忽视的:它的时间复杂度太高了!一旦遇见长的字符串就会让程序运行时间指数型增长。而用KMP算法可以很好的解决代码的时间复杂度高的问题,它的时间复杂度是线性的,也就是说该算法的时间复杂度取决于两个字符串的长度。
接下来我会对KMP算法完成任务的大概思路进行叙述
首先,我们约定一些符号:S为主字符串,也就是被进行查找的字符串;P为子字符串,也就是需要查找的字符串;next为next数组,里面记录了一些解决任务的关键信息,这里先买一些关子,毕竟比较难解释。
然后就是给定一个主字符串S = ‘ACBACC DBACBACDEA’,子字符串P = ‘ACBACD’,next = [-1, 0, 0, 0, 1, 2]
接着开始比对
如上图,当i = 0,j = 0时,二者相等,所以i和j皆进一位;
当i = 1,j = 1时,二者相等,所以i和j皆进一位;
当i = 2,j = 2时,二者相等,所以i和j皆进一位;
当i = 3,j = 3时,二者相等,所以i和j皆进一位;
当i = 4,j = 4时,二者相等,所以i和j皆进一位;
当i = 5,j = 5时,二者不相等,所以把j = next[j] = 3,i不变;
(箭头表示当前在比较的位置)
当i = 5,j = 2时,二者相等,所以i和j皆进一位;
当i = 6,j = 3时,二者不相等,所以把j = next[j] = 0,i不变;
(箭头表示当前在比较的位置)
当i = 6,j = 0时,二者不相等,所以把j = next[j] = -1,i不变;
当i = 6,j = -1时,此时j为特殊值,所以i和j皆进一位;
当i = 7,j = 0时,二者不相等,所以把j = next[j] = -1,i不变;
当i = 7,j = -1时,此时j为特殊值,所以i和j皆进一位;
当i = 8,j = 0时,二者不相等,所以把j = next[j] = -1,i不变;
当i = 8,j = -1时,此时j为特殊值,所以i和j皆进一位;
(箭头表示当前在比较的位置)
当i = 9,j = 0时,二者相等,所以i和j皆进一位;
当i = 10,j = 1时,二者相等,所以i和j皆进一位;
当i = 11,j = 2时,二者相等,所以i和j皆进一位;
当i = 12,j = 3时,二者相等,所以i和j皆进一位;
当i = 13,j = 4时,二者相等,所以i和j皆进一位;
当i = 14,j = 5时,二者相等,所以i和j皆进一位;
当i = 15,j = 6时,此时检测到j>len(P)了,则跳出循环;
最后返回布尔值,或者返回你想要得到的信息
如此,我们就走完了一次KMP算法,完成了一次任务,得到了正确的结果
通过上面的流程,我们可以得知KMP算法中有一个重要的部分:next数组。
那next数组是什么呢?next数组主要用于存储j位之前的字符串的最长相同前缀和后缀的长度。
(
什么是前缀、后缀呢?"前缀"指除了最后一个字符以外,一个字符串的全部头部组合;"后缀"指除了第一个字符以外,一个字符串的全部尾部组合。当然,这里指的是在j位之前包括j位的前后缀。
需要注意的是:假如有一个字符串“abcd”,那么其前缀是:a ab abc,其后缀是:bcd cd d。也就是说前后缀是不止一个的。
而前文所说的最长相同前缀和后缀的长度即是指:假若有一个字符串“aabab”,其前缀是:a aa aab aaba,其后缀是:aaba aba ba a,那这个的最长相同前后缀是a,所以该位置对应next数组的位置的值的应该是1。
练习:“abcabx” [0,0,0,1,2,0]
)
这里提供一个代码计算next数组的方法
- def get_next(son_str: str) -> list():
- """
- 获得next数组
- 参数解释 son_str: 需要求next数组的字符串
- 返回值: 返回next数组
- """
- length = len(son_str)
- # 定义next数组
- next = length*[None]
- next[0] = -1
- next[1] = 0
- # 计算next数组
- k = -1
- j = 0
- while j < length-1:
- if son_str[k] == son_str[j] or k == -1:
- j += 1
- k += 1
- next[j] = k
- else:
- k = next[k]
- return next
这里的next[0] = -1主要是因为方便代码处理j回到0时,发现S[i] != P[j]时,i无法进位的情况(用上面第一个方法求出的next数组也可用,但是具体方法得去搜索了,作者是使用的是代码求出来的那个next数组)
到此,该算法也已经讲得差不多了
下面提供完整的代码
- #!/usr/bin/env python
- # -*- encoding: utf-8 -*-
- '''
- @文件名 : KMP.py
- @描述 : 实现KMP算法,进行字符串比对
- @创建时间 : 2023/09/07/20
- @作者 : zrold
- @版本 : 1.0
- '''
- def kmp(farther_str: str, son_str: str) -> bool:
- """
- 定义KMP算法, 并根据传进来的两个参数来进行比对, 并返回一个布尔值
- 参数解释: farther_str: 进行比对的主字符串,
- son_str: 子字符串
- 返回值: 返回一个布尔值
- """
- # 得到next数组
- next = get_next(son_str)
- # 匹配字符串
- i = 0
- j = 0
- while i < len(farther_str) and j < len(son_str):
- if farther_str[i] == son_str[j] or j == -1:
- i += 1
- j += 1
- else:
- j = next[j]
- if j >= len(son_str):
- return True
- else:
- return False
- def get_next(son_str: str) -> list():
- """
- 获得next数组
- 参数解释 son_str: 需要求next数组的字符串
- 返回值: 返回next数组
- """
- length = len(son_str)
- # 定义next数组
- next = length*[None]
- next[0] = -1
- next[1] = 0
- # 计算next数组
- k = -1
- j = 0
- while j < length-1:
- if son_str[k] == son_str[j] or k == -1:
- j += 1
- k += 1
- next[j] = k
- else:
- k = next[k]
- return next
- if __name__ == '__main__':
- farther_str = input('请输入需要进行对比的主字符串:')
- son_str = input('请输入需要在主字符串中找到的子字符串:')
- if kmp(farther_str, son_str):
- print(f'确实存在"{son_str}"在"{farther_str}"中')
- else:
- print(f'不存在"{son_str}"在"{farther_str}"中')
KMP字符串对比算法及next数组计算的更多相关文章
- 字符串(马拉车算法,后缀数组,稀疏表):BZOJ 3676 [Apio2014]回文串
Description 考虑一个只包含小写拉丁字母的字符串s.我们定义s的一个子串t的“出 现值”为t在s中的出现次数乘以t的长度.请你求出s的所有回文子串中的最 大出现值. Input 输入只有一行 ...
- KMP字符串查找算法
#include <iostream> #include <windows.h> using namespace std; void get_next(char *str,in ...
- 字符串类——KMP子串查找算法
1, 如何在目标字符串 s 中,查找是否存在子串 p(本文代码已集成到字符串类——字符串类的创建(上)中,这里讲述KMP实现原理) ? 1,朴素算法: 2,朴素解法的问题: 1,问题:有时候右移一位是 ...
- poj 2406:Power Strings(KMP算法,next[]数组的理解)
Power Strings Time Limit: 3000MS Memory Limit: 65536K Total Submissions: 30069 Accepted: 12553 D ...
- 字符串匹配KMP算法中Next[]数组和Nextval[]数组求法
数据结构课本上给了这么一段算法求nextval9[]数组 int get_nextval(SString T,int &nextval[ ]) { //求模式串T的next函数修正值并存入数组 ...
- KMP算法的next[]数组通俗解释
原文:https://blog.csdn.net/yearn520/article/details/6729426 我们在一个母字符串中查找一个子字符串有很多方法.KMP是一种最常见的改进算法,它可以 ...
- hdu 1358:Period(KMP算法,next[]数组的使用)
Period Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)Total Subm ...
- KMP 算法 & 字符串查找算法
KMP算法 Knuth–Morris–Pratt algorithm 克努斯-莫里斯-普拉特 算法 algorithm kmp_search: input: an array of character ...
- KMP字符串模式匹配详解(zz)
刚看到位兄弟也贴了份KMP算法说明,但本人觉得说的不是很详细,当初我在看这个算法的时候也看的头晕昏昏的,我贴的这份也是网上找的.且听详细分解: KMP字符串模式匹配详解 来自CSDN A_B_ ...
- KMP字符串模式匹配详解(转)
来自CSDN A_B_C_ABC 网友 KMP字符串模式匹配通俗点说就是一种在一个字符串中定位另一个串的高效算法.简单匹配算法的时间复杂度为O(m*n);KMP匹配算法.可以证明它的时间复杂度 ...
随机推荐
- 源代码管理工具——Git
Git是一个开源的分布式版本控制系统,用于管理软件开发中的版本控制和协作.通过Git,开发人员可以记录文件的修改历史.协作开发,以及在多个分支上进行实验性开发.Git已成为现代软件开发中不可或缺的工具 ...
- 瞄准程序员招聘痛点,ShowMeBug让面试代码操作可“回放”
程序员虽然是建设互联网的职业之一,但他们的招聘工作的线上化却有不少难题. 疫情加速了市场对远程办公.远程面试.远程教学等模式的接受程度,但程序员招聘涉及到代码能力测试,甚至不同企业有不同的产品代码基础 ...
- Doris(五) -- 数据的导入导出
数据导入 使用 Insert 方式同步数据 用户可以通过 MySQL 协议,使用 INSERT 语句进行数据导入 INSERT 语句的使用方式和 MySQL 等数据库中 INSERT 语句的使用方式类 ...
- element-ui中Select 选择器异步加载下一页
场景 当我们使用 Select 选择器存放大量数据的时候. 会发现存在这么2个问题. 1.接口响应时间较长.(因为数据量较多,一次查询的所有)甚至有可能超时. 2.前端下拉框滑动卡顿. 这个时候们如何 ...
- Serverless云上作战阵型 | 通过云函数使用云数据库快速突破音障
随着航空塔台的指令在耳边响起,飞行员奔向此次作战行动的两架座机.雷厉风行的爬进驾驶舱,关上舱盖,迅速下载简化操作的Demo包到机载电脑,从容的打开发动机,驾驶战斗机缓缓滑入跑道,后面僚机也已准备就绪. ...
- 带你彻底掌握Bean的生命周期
摘要:我们将深入研究Spring Framework的核心部分--Spring Bean的生命周期. 本文分享自华为云社区<Spring高手之路5--彻底掌握Bean的生命周期>,作者: ...
- 逍遥自在学C语言 | 函数初级到高级解析
前言 函数是C语言中的基本构建块之一,它允许我们将代码组织成可重用.模块化的单元. 本文将逐步介绍C语言函数的基础概念.参数传递.返回值.递归以及内联函数和匿名函数. 一.人物简介 第一位闪亮登场,有 ...
- 【序列化与反序列化】关于序列化与反序列化MessagePack的实践
在进行序列化操作之前,我们还对系统进行压测,通过jvisualvm分析cpu,线程,垃圾回收情况等:运用火焰图async-profiler分析系统性能,找出程序中占用CPU资源时间最长的代码块. 代码 ...
- 十大功能特性,助力开发者玩转API Explorer
摘要:华为云API Explorer为开发者提供一站式API解决方案统一平台,集成华为云服务所有开放API,支持全量快速检索.可视化调试.帮助文档.代码示例等能力,帮助开发者快速查找.学习API和使用 ...
- Lock同步_小记
使用同步机制的这种方式解决线程安全问题,但是不知道具体的锁对象在哪里添加,并且锁对象在哪里释放锁对象,对于这种情况Jdk5以后Java提供了一个更具体的锁对象:Lock Lock 实现提供了比使用 s ...