KMP算法(kmp) next数组算法解析

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: KMP算法(kmp) next数组算法解析

关于KMP算法,CSDN有很多优质的博文,结合各位大佬的总结,我按照自己的想法尽量解释KMP算法(全文没有推导公式,因为我也不会。)

先简单介绍一下KMP算法的内容:

相对于暴力算法,KMP算法的时间复杂度较小,只回溯模式串中i,(i对应模式串的位置,j对应主串的位置),KMP算法模式串不需要回溯到第一位,只需要利用前缀和后缀,这样子的话就可以一次性得挪动好几位,以此来缩小时间复杂度,核心思想是将主串中的后缀和模式串中的前缀对齐,然后进行比较后面的部分;

微信图片_20220927110638.png显然,主串和模式串在第六个位置时,处于失配状态,此时模式串中的前缀和后缀为 a b,将模式串的前缀和主串的后缀进行对齐,这样子的话就可以直接从模式串的第三个位置进行比较即可。整体思路就是上述所说的内容,然后需要解决的问题是如何找前缀和后缀所相等的最大长度,这里我们引入了数组next进行解决,

先解释一下next数组的作用: next[i]的值表示下标为i的字符前的字符串最长相等前后缀的长度+1。 第二个作用是说字符串不匹配时需要回溯的位置。

KMP算法的精髓在于next数组,首先解释next数组中的值代表的意义:

补充前缀和后缀的概念 eg:前缀指的是一串字符串中除了最后一个字符外的所有字符按照顺序排列的集合,字符串a b c d 他的前缀分别是{a}{a,b}{a,b,c};后缀指的是一串字符串中除了第一个字符外的所有字符按顺序排列的集合,字符串a,b,c,d他的后缀分别是{d}{c,d}{b,c,d};关于前缀和后缀的问题,CSDN有很多优质的博文去解释这个问题,我相信她们比我解释的好。

eg:a b a c next【4】指在第四元素之前的三个元素中,前缀和后缀相同的最大长度为1+1=2,所以next【4】=2;前缀和后缀相同的最大长度为1,但是得再加1,原因是要进行匹配,所以都得在最后加上1

next【0】数组没有实际意义,模式串的第一个字符从next【1】进行存储,当然next【0】也可以存放数组的长度

前缀用j表示,后缀用i表示;

小总结:在做求next【】的值时,总要在最大长度之后加上1

关于代码部分,总体思路是从中间取i,j的值,这样子可以更好的加深对代码的分析,我只能解释代码,不会写代码。注意此处取的不是特殊值,它反映的是已汇总普遍的现象。

eg:字符串a b a b a a a b a(字符之间没有空格,打空格是为了方便看)

微信图片_20220927110715.png

假设起初i指向的是第三个元素,j将指向的是第一个元素,所以i指向的是字符a,j指向的是字符a;微信图片_20220927110721.png

(此处的i,j不是指针,使用箭头是方便认出)

很清楚的可以看出,此时i ,j分别指着两个a,a==a,表明字符串匹配成功,则继续下一个字符串的匹配,

此处的代码可以表示为:

if(next[i]==next[j])
{
  i++;
  j++;
  next[i]=j;
}

解释代码 next[i]=j;

因为执行完代码i++; j++;之后,此时i=4,j=2;next【4】=2;此处说明一下,前缀j是可以填充next【i+1】值的关键所在,j永远是从第一个字符串开始,j的改变说明这一串字符中有多少个相同的前缀和后缀,j往后移动一位,说明前缀和后缀相同的字符个数+1;而next【i】中存储的值永远表明在i之前的i-1字符中,前缀和后缀的相同字符串的数目。

i和j同步往后移,直到j=b,i=a时,此时next【j】!=next【i】,在此之前,匹配相同的字符串是aba

微信图片_20220927110832.png微信图片_20220927110837.png

当遇到next【i】!= next【j】时,

代码:

else
{
  j=next[j];
}
1

此时j要进行回溯。

先解释一个结论:next[j+1]的最大值为next[j]+1

这个结论不懂也可以;后面举例说明:

要求next【17】的值,已知next【16】=8,说明前缀后缀最大重叠度为7,

若next【8】==next【16】,则next【17】=8+1=9

微信图片_20220927111029.png

若next【8】!=next【16】,则j=next【j】;j回溯到next【8】,

假设next【8】==4;

微信图片_20220927111102.png

根据对称性。所以可以得出:

微信图片_20220927111142.png

所以可以得出:(荧光深蓝色部分相同)微信图片_20220927111224.png

若果next【4】==next【16】,继续执行 i++;j++;程序,若果next【4】!=next【16】;则按照上面的方法继续讨论;

按照这个样子以此类推,就可以得出next数组的值;

上述过程为next函数的大体框架,接下来介绍next数组的一些边角料;

代码:j=0;i=1;while循环判断的条件是while(i<next【0】);此处next【0】的内容为字符串的串长,

总体代码:


//

void get_next(String T,int *next)
{
  i=0;j=1;
  next[1]=0;
  if(j=0||T[i]==T[j])
  {
    i++;
    j++;
    next[i]=j;
  }
  else
  {
    j=next[j];
  }
}
相关文章
|
1月前
|
算法 前端开发 数据处理
小白学python-深入解析一位字符判定算法
小白学python-深入解析一位字符判定算法
47 0
|
1月前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
41 3
|
1月前
|
搜索推荐 算法
插入排序算法的平均时间复杂度解析
【10月更文挑战第12天】 插入排序是一种简单直观的排序算法,通过不断将未排序元素插入到已排序部分的合适位置来完成排序。其平均时间复杂度为$O(n^2)$,适用于小规模或部分有序的数据。尽管效率不高,但在特定场景下仍具优势。
|
16天前
|
算法 Linux 定位技术
Linux内核中的进程调度算法解析####
【10月更文挑战第29天】 本文深入剖析了Linux操作系统的心脏——内核中至关重要的组成部分之一,即进程调度机制。不同于传统的摘要概述,我们将通过一段引人入胜的故事线来揭开进程调度算法的神秘面纱,展现其背后的精妙设计与复杂逻辑,让读者仿佛跟随一位虚拟的“进程侦探”,一步步探索Linux如何高效、公平地管理众多进程,确保系统资源的最优分配与利用。 ####
50 4
|
17天前
|
缓存 负载均衡 算法
Linux内核中的进程调度算法解析####
本文深入探讨了Linux操作系统核心组件之一——进程调度器,着重分析了其采用的CFS(完全公平调度器)算法。不同于传统摘要对研究背景、方法、结果和结论的概述,本文摘要将直接揭示CFS算法的核心优势及其在现代多核处理器环境下如何实现高效、公平的资源分配,同时简要提及该算法如何优化系统响应时间和吞吐量,为读者快速构建对Linux进程调度机制的认知框架。 ####
|
20天前
|
UED
<大厂实战经验> Flutter&鸿蒙next 中使用 initState 和 mounted 处理异步请求的详细解析
在 Flutter 开发中,处理异步请求是常见需求。本文详细介绍了如何在 `initState` 中触发异步请求,并使用 `mounted` 属性确保在适当时机更新 UI。通过示例代码,展示了如何安全地进行异步操作和处理异常,避免在组件卸载后更新 UI 的问题。希望本文能帮助你更好地理解和应用 Flutter 中的异步处理。
61 3
|
20天前
|
JavaScript API 开发工具
<大厂实战场景> ~ Flutter&鸿蒙next 解析后端返回的 HTML 数据详解
本文介绍了如何在 Flutter 中解析后端返回的 HTML 数据。首先解释了 HTML 解析的概念,然后详细介绍了使用 `http` 和 `html` 库的步骤,包括添加依赖、获取 HTML 数据、解析 HTML 内容和在 Flutter UI 中显示解析结果。通过具体的代码示例,展示了如何从 URL 获取 HTML 并提取特定信息,如链接列表。希望本文能帮助你在 Flutter 应用中更好地处理 HTML 数据。
100 1
|
20天前
|
Dart 安全 编译器
Flutter结合鸿蒙next 中数据类型转换的高级用法:dynamic 类型与其他类型的转换解析
在 Flutter 开发中,`dynamic` 类型提供了灵活性,但也带来了类型安全性问题。本文深入探讨 `dynamic` 类型及其与其他类型的转换,介绍如何使用 `as` 关键字、`is` 操作符和 `whereType&lt;T&gt;()` 方法进行类型转换,并提供最佳实践,包括避免过度使用 `dynamic`、使用 Null Safety 和异常处理,帮助开发者提高代码的可读性和可维护性。
69 1
|
1月前
|
人工智能 前端开发 JavaScript
拿下奇怪的前端报错(一):报错信息是一个看不懂的数字数组Buffer(475) [Uint8Array],让AI大模型帮忙解析
本文介绍了前端开发中遇到的奇怪报错问题,特别是当错误信息不明确时的处理方法。作者分享了自己通过还原代码、试错等方式解决问题的经验,并以一个Vue3+TypeScript项目的构建失败为例,详细解析了如何从错误信息中定位问题,最终通过解读错误信息中的ASCII码找到了具体的错误文件。文章强调了基础知识的重要性,并鼓励读者遇到类似问题时不要慌张,耐心分析。
|
1月前
|
机器学习/深度学习 算法 PyTorch
Pytorch-RMSprop算法解析
关注B站【肆十二】,观看更多实战教学视频。本期介绍深度学习中的RMSprop优化算法,通过调整每个参数的学习率来优化模型训练。示例代码使用PyTorch实现,详细解析了RMSprop的参数及其作用。适合初学者了解和实践。
37 1

推荐镜像

更多