KMP字符串匹配算法

介绍:

KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是通过一个next()函数实现,函数本身包含了模式串的局部匹配信息。KMP算法的时间复杂度O(m+n) 。

算法:

1 能解决什么问题

解决字符串匹配问题,有一个字符串A ,有个字符串B,问A是否包含B,如果包含返回A串与B串匹配开头的数组下标,如果不匹配则返回-1

A:abcabcdabce

B:abce

我们可以看到,A串的最后四个字符是和B串一样的,所以是可以匹配上的,但如果写代码逻辑,我们需要写两层循环,首先循环A的第一个和B的第一个进行比较,如果匹配上了,那A的第二个和B的第二个去继续匹配,直到B都匹配上,如果没匹配上,则是再从A的第二个字符和B的第一个字符再进行比较,直到循环匹配上或A的所有字符都比较完,停止循环。

这个基本的算法,时间复杂度是O(m*n),如果遇到很大的串,就会很慢,而KMP可以将时间复杂度降到O(m+n),这里m是指A串的长度,n是指B串的长度。

2算法引入

A:abcabcdabce

B:abce

还是这个串,我们用眼睛直接去做比对,来探寻一下,大脑是怎么匹配的。

        首先,我先看到了第一个字符都是a,然后我继续看到了开头都是abc,发现匹配上了3个,就差最后一个了,我再看A串第四个竟然是a不是e,这里难免有点小沮丧。

        但是我不会从A串的b开始匹配,因为我之间都比较过了嘛,abc中间的bc是不能再匹配上的,很明显,我从A串的四个会开始匹配,这个时候我有看到了一个abc 这个 abcabcdabce,然后发现结尾又是个d,哎,只能再匹配了,但我也不会从d匹配,因为B串开头是a嘛,然后从d后面开始匹配,最后匹配到了abce

        从这个过程可以看出,我通过之前的比较,脑子记了一些东西,得出,如果按顺序继续暴力的去匹配,肯定匹配不上的结论,从而减少了匹配的次数,更快的完成了匹配。

        KMP就是这样,他通过一些数据记录,从而避免了多余无效的比较,并且还能他给出当前最能匹配多长的串下标是哪个,从而继续匹配。

3 算法逻辑

算法主体分为2部分,1 是生成next数组 2是匹配 

1 next数组生成

next数组,这个是由于字符串B进行生成的,是匹配过程中的工具,我们先看下如何生成next数组

A:abcabcabce

B:abcabce

需要新建一个next数组 长度和B串的长度一样,然后算出数据如下

abcabce
-1000123

说下 这个数字是怎么算的

abcabce  e字符前面 abcabce  是一样的,代表前面有3个一样的 所以e下面是3

再多几个例子

  aab  分别是-1 0 1 因为a和a对称

aaab  分别是-1 0 1 2 因为a和a对称   aa 和 aa对称,

aaaba  分别是-1 0 1 2  0因为a和a对称   aa 和 aa对称,最后一个a前面就没对称的了

再说咱们的字符B是怎么算的

第一个字符 和第二个字符 默认 -1 0 

第三个字符c 看 第一个字符a和第二个字符b 判断不是对称

第四个字符a  首先第三个字符c下面的数据是0,第一个字符a和第二个字符c判断不对称,所以写0

第五个字符b 首先第四个字符a下面是0,第五个字符开始对比 第四个字符和第一个字符,一样,所以写1

第六个字符c 先看第五个字符b下面是1,所以下标1代表第二个字符,拿第二个字符和第五个字符比,一样,所以第五字符值+1 = 2 ,第六个字符写2 

第七个字符e先看第六个字符c下面是2,所以下标2代表第三个字符,拿第三个字符和第六个字符比,一样,所以第六字符值+1 = 3 ,第七个字符写3  

2 匹配 

A:abcabcabce

B:abcabce

abcabce
-1000123

循环匹配,条件

1 循环A B 串进行匹配,直到匹配到了,或者匹配到A最后一个字符结束

2 进行一次匹配,我们发现按照顺序匹配A串和B串能匹配到第六个字符,当第七个字符a和e匹配的时候是匹配不上的,这个时候就要用到next数组了,e下面是三,所以 B下标匹配调到下标3的位置也就是第四个字符a,和A串的第七个字符a匹配,匹配上了,然后继续

A:abcabcabce

B:abcabce

3 大家发现,利用next串因为标注了B串对称的下标,又因为A串匹配到的和B串当前位置的之前都一样,所以根据next数组,直接就能跳过之前的匹配,减少了很多无用的比较。

4 假设B的第四个字符a和A的第七个字符是匹配不上的,那就要再看next数组,第四个字符对应0,所以就跳到0,也就是第一个字符再和A的第七个字符比较。

代码:


public class KMP {public static int getIndexOf(String s1, String s2) {//判断如果不需要比较就跳出if (s1 == null || s2 == null || s2.length() < 1 || s1.length() < s2.length()) {return -1;}char[] str1 = s1.toCharArray();char[] str2 = s2.toCharArray();//x是str1 下标 y是str2下标int x = 0;int y = 0;// O(M) m <= n   获取next数组int[] next = getNextArray(str2);// O(N) 循环知道x 或者 y 超出 字符串最大长度 匹配结束,这里x条件跳出说明str1已经都比较过了,y跳出说明已经都匹配上了while (x < str1.length && y < str2.length) {if (str1[x] == str2[y]) {//如果匹配上了x 和 y都加1x++;y++;} else if (next[y] == -1) { // y == 0//没匹配上,但是y已经是0了, y0的位置next数组是一定等于-1的x++;} else {//如果没匹配上,获取next数组中的值,根据值的下标继续用当前x位置和获取到的Y位置进行比较y = next[y];}}return y == str2.length ? x - y : -1;}public static int[] getNextArray(char[] str2) {if (str2.length == 1) {return new int[] { -1 };}int[] next = new int[str2.length];next[0] = -1;next[1] = 0;int i = 2; // 目前在哪个位置上求next数组的值int cn = 0; // 这个记录者着之前能匹配到最大的前串尾巴,当前是哪个位置的值再和i-1位置的字符比较while (i < next.length) {if (str2[i - 1] == str2[cn]) {// 配成功的时候  把cn+1后放到i位置,然后i++next[i++] = ++cn;} else if (cn > 0) {//匹配没成功,继续匹配比他小的可匹配串cn = next[cn];} else {//否则cn=0说明没有课匹配的了 直接给i赋值0next[i++] = 0;}}return next;}// for testpublic static String getRandomString(int possibilities, int size) {char[] ans = new char[(int) (Math.random() * size) + 1];for (int i = 0; i < ans.length; i++) {ans[i] = (char) ((int) (Math.random() * possibilities) + 'a');}return String.valueOf(ans);}public static void main(String[] args) {int possibilities = 5;int strSize = 20;int matchSize = 5;int testTimes = 5000000;System.out.println("test begin");for (int i = 0; i < testTimes; i++) {String str = getRandomString(possibilities, strSize);String match = getRandomString(possibilities, matchSize);if (getIndexOf(str, match) != str.indexOf(match)) {System.out.println("Oops!");}}System.out.println("test finish");}}

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

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

相关文章

绘制太极图 - 使用 PyQt

大家好&#xff01;今天我们将一起来探讨一下如何使用PyQt&#xff0c;这是一个强大的Python库&#xff0c;来绘制一个传统的太极图。这个图案代表着古老的阴阳哲学&#xff0c;而我们的代码将以大白话的方式向你揭示它的奥秘。 PyQt&#xff1a;是什么鬼&#xff1f; 首先&a…

C# 中的接口

简介 官方说明&#xff1a;接口定义协定。 实现该协定的任何 class 或 struct 必须提供接口中定义的成员的实现。 接口可为成员定义默认实现。 它还可以定义 static 成员&#xff0c;以便提供常见功能的单个实现。 从 C# 11 开始&#xff0c;接口可以定义 static abstract 或 …

【AI-Pos系列】DeepLabCut 学习

level: nature neuroscience author:Alexander Mathis  1,2, Pranav Mamidanna1 , Kevin M. Cury3 , Taiga Abe3 , Venkatesh N. Murthy  2 , Mackenzie Weygandt Mathis  1,4,8* and Matthias Bethge1,5,6,7,8 date: 2018 keyword: quantifying behavior; pose estimation;…

超级胶水(第十一届蓝桥杯)

题目 小明有 n n n颗石子&#xff0c;按顺序摆成一排。他准备用胶水将这些石子粘在一起。 每颗石子有自己的重量&#xff0c;如果将两颗石子粘在一起&#xff0c;将合并成一颗新的石子&#xff0c;重量是这两颗石子的重量之和。 为了保证石子粘贴牢固&#xff0c;粘贴两颗石…

架构师之路(十六)计算机网络(传输层)

前置知识&#xff08;了解&#xff09;&#xff1a;计算机基础。 作为架构师&#xff0c;我们所设计的系统很少为单机系统&#xff0c;因此有必要了解计算机和计算机之间是怎么联系的。局域网的集群和混合云的网络有啥区别。系统交互的时候网络会存在什么瓶颈。 既然网络层已经…

.net访问oracle数据库性能问题

问题&#xff1a; 生产环境相同的inser语句在别的非.NET程序相应明显快于.NET程序&#xff0c;执行时间相差比较大&#xff0c;影响正常业务运行&#xff0c;测试环境反而正常。 问题详细诊断过程 问题初步判断诊断过程&#xff1a; 查询插入慢的sql_id 检查对应的执行计划…

直播间流程解析基础

通过用户心理需求引导用户行为 贯穿内容和产品牵引想要和需要 直播间内流程解析 分为播前准备、开播暖场、产品介绍、穿插活动、结尾预告 &#xff08;1&#xff09;直播间内流程解析----播前准备 &#xff08;2&#xff09;直播间内流程解析----开播暖场 &#xff08;3&…

互联网加竞赛 基于机器视觉的银行卡识别系统 - opencv python

1 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 基于深度学习的银行卡识别算法设计 该项目较为新颖&#xff0c;适合作为竞赛课题方向&#xff0c;学长非常推荐&#xff01; &#x1f9ff; 更多资料, 项目分享&#xff1a; https://gitee.com/dancheng…

电涌保护器(SPD)、后备保护器(SCB)、断路器(CB)的区别与应用

随着现代电力系统的不断发展&#xff0c;电力设备的保护显得愈发重要。其中&#xff0c;电涌保护器&#xff08;SPD&#xff09;、后备保护器&#xff08;SCB&#xff09;和断路器&#xff08;CB&#xff09;是三种常见的保护设备&#xff0c;但它们各自具有不同的功能和特点。…

【渗透测试】借助PDF进行XSS漏洞攻击

简介 在平时工作渗透测试一个系统时&#xff0c;常常会遇到文件上传功能点&#xff0c;其中大部分会有白名单或者黑名单机制&#xff0c;很难一句话木马上传成功&#xff0c;而PDF则是被忽略的一个点&#xff0c;可以让测试报告更丰富一些。 含有XSS的PDF制作步骤 1. 编辑器…

论文阅读《thanking frequency fordeepfake detection》

项目链接&#xff1a;https://github.com/yyk-wew/F3Net 这篇论文从频域的角度出发&#xff0c;提出了频域感知模型用于deepfake检测的模型 整体架构图&#xff1a; 1.FAD&#xff1a; 频域感知分解&#xff0c;其实就是利用DCT变换&#xff0c;将空间域转换为频域&#xff…

element+vue 之 v-limit 按钮操作权限

1.新建一个permission.js文件 import store from /storeexport default {inserted: function (el, binding) {const { perms: limits } store.state.userconst { value: params } bindingif (!limits.length) returnif (params && Array.isArray(params)) {if (!limi…

如何利用PyTorch?

上一篇文章介绍了“What is PyTorch?”,本篇文章探讨一下“How to use PyTorch&#xff1f;” 1、PyTorch PyTorch 是一个开源机器学习库&#xff0c;基于 Torch 库开发&#xff0c;主要由 Facebook 的人工智能研究实验室&#xff08;FAIR&#xff09;研发。它是一个强大且灵…

【备忘】thinkphp5.1之websocket长连接框架使用流程简述

前言 本文纯属经验备注&#xff0c;有许多地方未进行测试&#xff0c;请勿照搬&#xff0c;仅供参考。 之前专门花了几天时间测试了websocket&#xff0c;当时只记得踩了许多坑&#xff0c;但是没有对测试流程进行记录&#xff0c;导致长时间未使用从而无从下手。 今天就简单…

08.Elasticsearch应用(八)

Elasticsearch应用&#xff08;八&#xff09; 1.为什么需要相关性算分 我们在文档搜索的时候&#xff0c;匹配程度越高的相关性算分越高&#xff0c;算分越高的越靠前&#xff0c;但是有时候我们不需要算分越高越靠前我们可能需要手动影响算分来控制顺序比如广告&#xff08…

2016年认证杯SPSSPRO杯数学建模A题(第一阶段)洗衣机全过程文档及程序

2016年认证杯SPSSPRO杯数学建模 A题 洗衣机 原题再现&#xff1a; 洗衣机是普及率极高的家用电器&#xff0c;它给人们的生活带来了很大的方便。家用洗衣机从工作方式来看&#xff0c;有波轮式、滚筒式、搅拌式等若干种类。在此基础上&#xff0c;各厂商也推出了多种具体方案…

微信小程序(十五)自定义导航栏

注释很详细&#xff0c;直接上代码 上一篇 新增内容&#xff1a; 1.组件文件夹创建方法 2.自定义组件的配置方法 3.外部修改组件样式&#xff08;关闭样式隔离或传参&#xff09; 创建组件文件夹 如果是手动创建建议注意在json文件声明&#xff1a; mynav.json {//声明为组件可…

从CDN了解到的边缘计算与前端渲染

文章概叙 本文代码量较少&#xff0c;讲的是在云开发的基础上使用边缘计算的&#xff0c;代码量不高&#xff0c;​建议看完理解下就可以丢了&#xff0c;知道个概念就好。 废话1 第一次接触边缘计算是在2020年的时候&#xff0c;公司的cloud课程中&#xff0c;有一些相关概…

2024年第四届机器人与人工智能国际会议(JCRAI 2024) | Ei、Scopus双检索

会议简介 Brief Introduction 2024年第四届机器人与人工智能国际会议(JCRAI 2024) 会议时间&#xff1a;2024年8月9日-11日 召开地点&#xff1a;中国上海 大会官网&#xff1a;www.jcrai.org 人工智能和机器人技术在过去几十年里得到了长足的发展&#xff0c;为未来的机器人应…

php二次开发股票系统代码:腾讯股票数据接口地址、批量获取股票信息、转换为腾讯接口指定的股票格式

1、腾讯股票数据控制器 <?php namespace app\index\controller;use think\Model; use think\Db;const BASE_URL http://aaaaaa.aaaaa.com; //腾讯数据地址class TencentStocks extends Home { //里面具体的方法 }2、请求接口返回内容 function juhecurl($url, $params f…