KMP算法详解

news2024/12/29 10:58:58

注意:PC阅读效果更佳,建议阅读的同时完成代码实践加深理解

一、问题描述

指定文本串:aabaabaaf和模式串:aabaaf

使用KMP算法判断模式串是否在文本串中出现过?

假定模式串的长度小于文本串

二、思路解析

BF算法的问题是:模式串已经匹配到最后一位了发现不一样,需要将文本串和模式串的指针都往后退,导致有很多的重复匹配,效率很低。

KMP算法的思路是,在发现某个字符不匹配的时候,充分利用前面已经匹配过的结果,不要把“搜索指针”回退到已经比较过的位置,而是把模式串往后移动到合适的位置继续比较。KMP算法只需要对文本串搜索一次,时间复杂度是O(n)。

三、检索过程图解

1918b8a47d3ec53abc22186dc45620c8.jpeg

四、部分匹配表

要理解部分匹配表,需要了解两个概念:前缀子串、后缀子串

  • 前缀子串:包含首字母,不包含尾字母的所有子串

  • 后缀子串:包含尾字母,不包含首字母的所有子串

例如:单词"bread"

  • 前缀子串:"b","br","bre","brea"

  • 后缀子串:"d","ad","ead","read"

部分匹配表中的数值含义是:当前这个字符前面的字符串中,相等的前缀子串和后缀子串的最大的长度。计算下aabaa的部分匹配表:

  • a:前缀子串集合和后缀子串集合都是空集,相等的前后缀子串的最大长度是0

  • aa:前缀子串集合是[a],后缀子串集合是[a],相等的前后缀子串的最大长度是1

  • aab:前缀子串集合是[a,aa],后缀子串集合是[b,ab],相等的前后缀子串的最大长度是0

  • aaba,前缀子串集合是[a,aa,aab],后缀子串集合是[a,ba,aba],相等的前后缀子串的最大长度是1

  • aabaa,前缀子串集合是[a,aa,aab,aaba],后缀子串集合是[a,aa,baa,abaa],相等的前后缀子串的最大长度是2

  • aabaaf,前缀子串集合是[a,aa,aab,aaba,aabaa],后缀子串集合是[f,af,aaf,baaf,abaaf],相等的前后缀子串的最大长度是0

“部分匹配表”的实质是,模式字符串中有时会有重复的子串,例如:aabaa的左右两边都有aa,那么该字符串的部分匹配值就是2,那么在发现aabaaf中的f不匹配的时候,只需要将aabaaf这个模式串往右移动3个位置,就可以让第一个aa来到第二个aa的位置。

edbcb83642c4bdc095007f6c33dc9581.jpeg

五、代码实现

算法课程或者题解中有一个常见的问题,变量命名很随意,i、j、next数组等等都是随意命名的结果,可读性很差,在下面的实现中我尽量是用可读性强的变量名,方便理解。

package org.javaadu.string;


import java.util.List;


public class StringSearchDemo {


    public static void main(String[] args) {
        String text = "aabaabaaf";
        String pattern = "aabaaf";


        boolean kmpRes = kmpSearch(text, pattern);
        System.out.println("kmpRes:" + kmpRes);
    }


    /**
     * 利用KMP算法求解pattern是否在text中出现过
     *
     * @param text    文本串
     * @param pattern 模式串
     * @return pattern在text中出现,则返回true,否则返回false
     */
    public static boolean kmpSearch(String text, String pattern) {
        //部分匹配数组,就是很多算法实现中的next数组
        int[] partMatchTable = buildPartMatchTable(pattern);
        //text中的指针
        int i = 0;
        //pattern中的指针
        int j = 0;


        while (i < text.length()) {
            if (text.charAt(i) == pattern.charAt(j)) {
                //字符匹配,则两个指针同时后移
                i++;
                j++;
            } else if (j > 0) {
                //字符失配,则利用next数组,异动j指针,避免i指针回退
                j = partMatchTable[j - 1];
            } else {
                //pattern中的第一个字符就失配了
                i++;
            }


            if (j == pattern.length()) {
                //搜索成功
                return true;
            }
        }
        return false;
    }


    private static int[] buildPartMatchTable(String pattern) {
        //初始化
        int[] partMatchTable = new int[pattern.length()];
        int prefixLen = 0;
        next[0] = 0;
        int i = 1;


        while (i < pattern.length()) {
            //pattern[prefixLen],表示目前最长相等子串的最后一位
            //pattern[i],表示目前正在处理的子串的最后一位的字符
            if (pattern.charAt(prefixLen) == pattern.charAt(i)) {
                //如果它俩相等,说明找到了更长的相等子串
                prefixLen++;


                partMatchTable[i] = prefixLen;
                i++;//处理下一个i的字符
            } else {
                //如果不相等,则需要尝试下更短1位的子串是否满足要求,因此这里要把再次循环尝试下:仅仅改变prefixLen的值,不改变i的值
                prefixLen = next[prefixLen - 1];
                if (prefixLen == 0) {
                    //如果实在没有合适的,则说明当前正在处理的子串的最长相等前后缀的长度是0
                    partMatchTable[i] = 0;
                    i++;//处理下一个i的字符
                }
            }
        }
        return partMatchTable;
    }
}

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

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

相关文章

【pytorch安装】conda安装pytorch无法安装cpu版本(完整解决过程)

问题描述 在安装pytorch过程中&#xff0c;发现最后验证torch时总是返回结果为False&#xff0c;结果翻上去发现自己安装的是cpu版本的。 然后又通过conda去更换不同版本尝试&#xff0c;发现都是cpu版本的。 问题分析 通过conda安装pytorch是从源中搜索匹配指令中的文件&am…

@Validated注解不生效问题汇总

Validated注解不生效问题汇总 文章目录Validated注解不生效问题汇总背景&#xff1a;一&#xff1a;可能原因原因1&#xff1a;原因2&#xff1a;原因3&#xff1a;原因4&#xff1a;二&#xff1a;补充全局异常对validation的处理背景&#xff1a; 项目框架应用的是validatio…

捕鱼大作战协议解密

捕鱼大作战协议解密协/议/流/量/解/密分析捕鱼大作战这款游戏流量的加密方式及解密方法。序捕鱼大作战是tuyoo公司在很多年前上线的一款休闲游戏&#xff0c;对&#xff0c;就是那个之前本号批斗过的途游&#xff0c;这款游戏以海洋深处作为背景&#xff0c;玩家通过在海底施展…

D31 Vue2 + Vue3 K104-K123

D31.Vue F17.打包 图片懒加载&#xff08;K104-K106&#xff09; 1.打包 1&#xff09;vue.config.js module.exports {//打包时不生成map文件(用来进行错误提示的文件&#xff0c;很占用空间)productionSourceMap: false,// 关闭ESLINT校验工具lintOnSave: false, }pnp…

学完Scrapy-Splash秒变爬虫大佬

在做爬虫的时候&#xff0c;大多数的网页中会存在数据动态加载的部分&#xff0c;而且多数都是后期渲染上的。正常情况下爬虫程序仅能爬取被渲染过的数据。因此我们看到的数据也许并非是爬虫直接获取来的。 而scrapy-splash担任了一个中间人的角色&#xff0c;程序通过splash服…

吴思进——复杂美创始人首席执行官

杭州复杂美科技有限公司创始人兼CEO, 本科毕业于浙江大学机械专业&#xff0c;辅修过多门管理课程&#xff1b;1997年获经济学硕士学位&#xff0c;有关对冲基金的毕业论文被评为优秀&#xff1b;2008年创办杭州复杂美科技有限公司。 吴思进 中国电子学会区块链委员会专家&…

计算机网络-基本概念

目录 计算机网络-基本概念 互联网 Java的跨平台原理 ​编辑 C\C的跨平台原理 解释性语言的跨平台原理(python,js等) 客户端 vs 服务器 什么是协议&#xff1f; 网络互连模型 请求过程 计算机之间的通信基础 计算机之间的连接方式-网线直连(需要用交叉线&#xff0c;而…

GIS数据经纬度投影坐标转换总结(涵盖几乎全行业的坐标转换方法)

在处理GIS数据的过程中,避免不了要与坐标和坐标系打交道。这篇文章对能够进行地理坐标转换的所有软件框架做一个一次性总结。 软件类: 1.arcgis arcgis能够进行很全面的很方便的坐标处理,无论是经纬度坐标转投影坐标还是投影坐标转经纬度坐标都非常的简单。arcgis能够对导…

Qt编写视频监控系统70-0SD标签和图形信息(支持写入到文件)

一、前言 作为一个完整的视频监控系统&#xff0c;用户还需要自定义一些OSD标签信息显示在对应通道上面&#xff0c;而且不止一个OSD标签信息&#xff0c;位置可以在四个角或者指定坐标显示。最开始本系统设计的时候&#xff0c;由于本人擅长的是painter绘制&#xff0c;所以直…

MySQL视图特性

文章目录MySQL视图特性基本使用准备测试表创建视图修改视图影响基表修改基表影响视图删除视图视图规则和限制MySQL视图特性 视图的概念 视图是一个虚拟表&#xff0c;其内容由查询定义&#xff0c;同真实的表一样&#xff0c;视图包含一系列带有名称的列和行数据。视图中的数据…

opencv读取摄像头和视频数据

大家好&#xff0c;我是csdn的博主&#xff1a;lqj_本人 这是我的个人博客主页&#xff1a; lqj_本人的博客_CSDN博客-微信小程序,前端,python领域博主lqj_本人擅长微信小程序,前端,python,等方面的知识https://blog.csdn.net/lbcyllqj?spm1011.2415.3001.5343哔哩哔哩欢迎关注…

TensorRT和DLA(Deep Learning Accelerator)

TensorRT和DLA(Deep Learning Accelerator) 点击此处加入NVIDIA开发者计划 文章目录TensorRT和DLA(Deep Learning Accelerator)12.1. Running On DLA During TensorRT Inference注意&#xff1a;对于任何张量&#xff0c;索引维度的总体积加上请求的批量大小不得超过此函数返回…

Docker 面试知识点

Docker 是什么&#xff1f; 是实现容器技术的一种工具是一个开源的应用容器引擎使用 C/S 架构模式&#xff0c;通过远程API 来管理 (我们本机是 C&#xff0c;docker 引擎是 S,实际的构建过程是在 docker 引擎下完成的)可以打包一个应用及依赖包到一个轻量级、可移植的容器中 …

Hbase 数据迁移

Hbase 数据迁移 可选方案对比 l 已验证方案操作说明&#xff1a; n Export&import u 导出命令及示例 hbase org.apache.hadoop.hbase.mapreduce.Export “表名” 文件路径 导出至本地文件系统&#xff1a; ./bin/hbase org.apache.hadoop.hbase.mapreduce.Export ‘defa…

UnityBurst系统批量计算的插件入门

什麽是Burst系統做一些批量計算需要&#xff0c;比较难用&#xff0c;针无两头利如果不需要“密集”计算&#xff0c;就帧的不需要&#xff0c;到底什么是密集计算呢&#xff0c;for循环不密集么&#xff0c;while循环不密集么&#xff1f;安装Burst因为发现一个不错项目的插件…

Zookeeper实现分布式锁

文章目录ZK节点类型watch监听机制Zookeeper实现分布式锁锁原理创建锁的过程释放锁的过程ZK锁的种类代码实现Zookeeper是一个开源的分布式协调服务&#xff0c;是一个典型的分布式数据一致性解决方案。 分布式应用程序可以基于Zookeeper实现诸如数据发布/订阅&#xff0c;负载均…

【C/C++基础练习题】简单指针与数组使用练习题

&#x1f349;内容专栏&#xff1a;【C/C要打好基础啊】 &#x1f349;本文内容&#xff1a;简单指针与数组练习题&#xff08;复习之前写过的实验报告&#xff09; &#x1f349;本文作者&#xff1a;Melon西西 &#x1f349;发布时间 &#xff1a;2023.2.12 目录 1.vector​编…

async thunk 解决 API 调用的依赖问题

async thunk 解决 API 调用的依赖问题 一句话节省看下面一堆内容的时间就是&#xff1a; async thunk 中可以使用 async/await 锁住其他的 action 操作 一般 API 之间存在三种情况&#xff1a; A 和 B 之间没有依赖关系 这样的情况下&#xff0c;A 和 B 可以各调用各的&#x…

最近大热的 chatGPT 会取代你的工作吗?

ChatGPT 由于其高效的自然语言处理能力&#xff0c;它最容易取代的领域可能是&#xff1a; 文本分类&#xff1a;ChatGPT 可以用作文本分类系统&#xff0c;对文本进行分类 聊天机器人&#xff1a;ChatGPT 可以制作聊天机器人&#xff0c;提供人性化的交互体验 文本生成&…

策略游戏与实践反馈

早上看到time&#xff08;李培楠&#xff09;居然击败maru得了IEM的冠军&#xff0c;加上即时战略游戏的没落&#xff0c;星际2的研发停止&#xff0c;以及最近曾经被大家膜拜的暴雪闹出的各种事情&#xff0c;各种百感交集吧&#xff0c;从2000年上手星际争霸1开始&#xff0c…