数据结构-KMP算法

server/2024/9/24 0:20:25/

KMP算法

  • 简单的模式匹配算法

    • 定义:子串的定位操作通常称为串的模式匹配,他求的是子串在主串中的位置
    • 过程
      • 逐个字符比较
        1. 从主串指针 i 对应的字符和模式串指针 j 对应的字符开始,依次比较它们是否相等。
        2. 若相等,则同时移动 i 和 j 向右一位,继续比较下一个字符。
      • 失配处理
        1. 若不相等,则表明当前子串不匹配,需要根据算法类型采取不同的策略:
        2. 朴素匹配:主串指针 i 回退一位(恢复到失配前的状态),模式串指针 j 重置为起始位置,然后继续比较。
        3. 模式匹配KMP:根据预先计算的模式串的部分匹配表,将模式串指针 j 直接移动到新位置(不回溯主串),继续比较。
  • 核心思想

    • 利用已知的匹配信息

      在进行字符串匹配的过程中,当模式串与主串在某个位置发生失配时,KMP算法意识到已有的部分匹配并没有被完全浪费。这是因为,从模式串的起始位置到失配点,有一段子串已经在主串中成功匹配。这一段已匹配的子串提供了关于模式串结构的重要信息。

    • 避免回溯主串

      • 在朴素的字符串匹配算法中,一旦发生失配,需要将模式串回溯到下一个位置(通常是前一个字符),然后继续从主串的同一位置开始重新比较。这种回溯过程可能导致大量的重复比较,尤其是在模式串中有较长相同前缀的情况下
      • KMP算法的核心创新在于,它通过预先计算的“部分匹配表”(LPS表)来确定模式串失配后的下一个起始比较位置,而不需要回溯主串。部分匹配表记录了模式串中每个前缀的最长相同真前缀(同时也是后缀)的长度。当失配发生时,可以根据当前失配点对应的部分匹配表值,直接将模式串滑动到主串中相应的新位置,继续比较,而不是回溯主串。
  • 部分匹配表(LPS)

    • 最长公共前后缀:
      • 对A这个子串,前缀集合,后缀集合都为空

      • 对AB这个子串,前缀集合{A},后缀集合{B}

      • 对于ABA这个子串,前缀集合{A,AB}后缀集合{A,BA}

      • 对于ABAB这个子串,前缀集合{A,AB,ABA}后缀集合{B,AB,BAB}

      • 对于ABABC这个子串,前缀集合{A,AB,ABA,ABAB},后缀集合{C,BC,ABC,BABC}

      • 从而得到他们的next数组,部分匹配表

        ABABC
        NEXT(最长公共前后缀长度)00120
  • 代码实现

        //获取KMP算法中的next数组public static int[] kmpNext(String dest){//创建next数组int[] next=new int[dest.length()];next[0]=0;//获取next数组for (int i=1,j=0;i<dest.length();i++){while (j>0&&dest.charAt(i)!=dest.charAt(j)){j=next[j-1];}if (dest.charAt(i)==dest.charAt(j)){j++;}next[i]=j;}return next;}//j变量的作用1.追踪最长相同真前缀:初始化时,j 被设置为 0,表示当前正在考虑的最长相同真前缀起始于模式串的第一个字符。在外层 for 循环中,随着 i 从 1 到 dest.length()-1 递增,j 用于追踪模式串中以第 i 个字符结尾的子串的最长相同真前缀的最后一个字符的索引。2.更新最长相同真前缀:当 dest.charAt(i) 与 dest.charAt(j) 相等时,说明当前字符可以延长最长相同真前缀,因此将 j 增加 1,继续追踪更长的相同真前缀。将 j 设置为 next[j-1],意味着将当前考虑的最长相同真前缀的起始位置回溯到这个较短的相同真前缀的起始位置。这样做可以避免重新检查那些已经确认匹配的字符,因为它们构成了相同的真前缀。
    
        /**** @param str1 模式串* @param str2 子串* @param next next数组* @return 若没找到返回-1,找到就返回在模式串中的下标*/public static int kmpSearch(String str1,String str2,int[] next){for (int i=0,j=0;i<str1.length();i++){while ((str1.charAt(i)!=str2.charAt(j))&&j>0){//通过next数组找到前一个位置子串的最长公共前后缀的索引值j=next[j-1];}if (str1.charAt(i)==str2.charAt(j)){j++;//子串索引后移}if (j==str2.length()){return i-j+1;}}return -1;}
    

http://www.ppmy.cn/server/17540.html

相关文章

适用于芯片行业的开发及管理工具:版本控制、持续集成、代码分析及项目管理工具介绍

3月28日-29日&#xff0c;2024国际集成电路展览会暨研讨会&#xff08;IIC Shanghai&#xff09;在上海成功举行。此次盛会汇聚了集成电路产业的众多领军企业&#xff0c;共同探寻和把握集成电路产业的发展脉络。 龙智携芯片研发及管理解决方案亮相展会&#xff0c;展示如何通…

计算机视觉 CV 八股分享 [自用](更新中......)

目录 一、深度学习中解决过拟合方法 二、深度学习中解决欠拟合方法 三、梯度消失和梯度爆炸 解决梯度消失的方法 解决梯度爆炸的方法 四、神经网络权重初始化方法 五、梯度下降法 六、BatchNorm 七、归一化方法 八、卷积 九、池化 十、激活函数 十一、预训练 十二…

Flutter开发之--初识Flutter

文章目录 概述Flutter整体架构嵌入层引擎层框架层 跑通demo尝鲜Flutter项目的目录介绍Flutter demo项目的运行 总结 概述 Flutter 是由Google公司研发的一种跨端开发技术&#xff0c;在2018年正式推出。Flutter自带Skia图形绘制引擎&#xff0c;采用自绘制的方式&#xff0c;不…

一次违法网站的渗透经历

0x01 前言 在一次攻防演练中&#xff0c;我发现了一个有趣的渗透路径。在信息收集阶段&#xff0c;我注意到目标网站和用户资产网站共享相同的IP网段。这意味着它们可能在同一台服务器上托管&#xff0c;或者至少由同一家互联网服务提供商管理。这种情况为我们的渗透测试提供了…

Redis 服务等过期策略和内存淘汰策略解析

redis服务是基于内存运行的&#xff0c;所以很多数据都存放在内存中&#xff0c;但是内存又不是无限的&#xff0c;所以redis就引出了key的过期和淘汰策略。 一、Redis的过期策略&#xff1a; 我们在set key的时候&#xff0c;可以给它设置一个过期时间&#xff0c;比如expire …

从C到Py:Python的字符串及正则表达式

在本篇博客中&#xff0c;我们将讲解Python中有关字符串及正则表达式的知识&#xff0c;在之前的文章中有较浅地提及字符串相关知识&#xff0c;但还不是比较完整。本次将较详细地介绍有关操作和诸多函数。 字符串的常用操作 字符串时是Python中的不可变数据类型&#xff0c;…

vue3+node.js+mysql+ant design实现表格的查询功能

今日主要分享如何运用vue、nodejs、mysql及ant design构建表格数据查询功能&#xff0c;这也是众多项目开发者关注的问题。最关键在于前端与后端的协作&#xff0c;后端数据则通过nodejs编写。尽管涉及多项技术&#xff0c;看似复杂&#xff0c;但实际操作却并非困难。当然&…

操作系统的IO模型有哪些

一、操作系统的IO场景 以Linux系统为例&#xff0c;对于Linux系统而言&#xff0c;everything is a file。因此&#xff0c;对于一个操作系统而言&#xff0c;一个基本的IO操作&#xff0c;设计两个系统对象&#xff1a; 一个是用户进程&#xff0c;一个是操作系统内核。 为了保…