【算法】KMP算法

news2024/9/26 1:19:46
应用场景
  1. 有一个字符串 str1 = "BBA ABCA ABCDAB ABCDABD",和一个子串 str2 = "ABCDABD"
  2. 现在要判断 str1 是否含有 str2,如果含有,就返回第一次出现的位置,如果不含有,则返回 -1

我们很容易想到暴力匹配算法

暴力匹配算法

如果用暴力匹配的思路,并假设现在 str1 匹配到 i 位置,子串 str2 匹配到 j 位置,则有

  1. 如果当前字符匹配成功(即 str1[i] == str2[j]),则 i++,j++,继续匹配下一字符
  2. 如果匹配失败,令 i = i - j + 1,j = 0。相当于每次匹配失败时,i 回溯,j 被置为 0
  3. 用暴力方法解决的话就会有大量的回溯,每次只移动一位,若是不匹配,移动到下一位接着判断,浪费了大量时间(不可行)

以下是代码实现暴力匹配

public class ViolenceMatch {
    public static void main(String[] args) {
         String str1 = "BBA ABCA ABCDAB ABCDABD";
         String str2 = "ABCDABD";
        System.out.printf("下标为%d", violenceMatch(str1, str2));
    }

    public static int violenceMatch(String str1, String str2) {
        char[] s1 = str1.toCharArray();
        char[] s2 = str2.toCharArray();

        int i = 0;  //储存s1 的下标
        int j = 0;  //储存s2 的下标

        while (i < s1.length && j < s2.length) {
            if (s1[i] == s2[j]) {
                i++;
                j++;
            } else {
                i = i - j + 1;
                j = 0;
            }
        }
        if (j == s2.length) {
            return i - j;
        }
        return -1;
    }
}

KMP算法

KMP算法介绍

KMP 算法利用之前判断过的信息,通过一个 next 数组,保存子串中前后最长公共子序列的长度,每次回溯时,通过 next 数组找到前面匹配过的位置,省去了大量计算时间

在学习KMP算法之前,我们先来聊一聊字符串的前缀与后缀

我们对子串 str2 建立一张《部分匹配表》

“部分匹配值”就是“前缀”和“后缀”的最长的共有元素的长度。以“ABCDABD”为例

“A”的前缀和后缀都为空集,共有元素的长度为0

“AB”的前缀为[A],后缀为[B],共有元素的长度为0

 “ABC”的前缀为[A,AB],后缀为[BC,C],共有元素的长度为0

 “ABCD”的前缀为[A,AB,ABC],后缀为[BCD,CD,D],共有元素的长度为0

“ABCDA”的前缀为[A,AB,ABC,ABCD],后缀为[BCDA,CDA,DA,A],共有元素为“A”,长度为 1

“ABCDAB”的前缀为[A,AB,ABC,ABCD,ABCDA],后缀为[BCDAB,CDAB,DAB,AB,B],共有元素为“AB”,长度为 1

“ABCDABD”的前缀为[A,AB,ABC,ABCD,ABCDA,ABCDAB],后缀为[BCDABD,CDABD,DABD,ABD,BD,D],共有元素的长度为 0

已知空格与 D 不匹配时,前面六个字符“ABCDAB”是匹配的。查表可知,最后一个匹配字符 B 对应的“部分匹配值”为 2,因此按照下面的公式算出向后移动的位数:

移动位数 = 已匹配的字符数 - 对应的部分匹配值

因为 6 - 2 = 4,所以将搜索词向后移动 4 位

public class KMPAlgorithm {
    public static void main(String[] args) {
        String str1 = "BBA ABCA ABCDAB ABCDABD";
        String str2 = "ABCDABD";
        int[] next = kmpNext(str2);
        System.out.println("str1 = " + str1);
        System.out.println("str2 = " + str2);
        System.out.println("next = " + Arrays.toString(next));
        int index = kmpSearch(str1, str2, next);
        System.out.printf("索引为%d", index);
    }

    //写出 KMP搜索算法
    /**
     *
     * @param str1
     * @param str2  子串
     * @param next  子串对应的部分匹配表
     * @return  返回第一个匹配的位置,如果是 -1 就没有匹配到
     */
    public static int kmpSearch(String str1, String str2, int[] next) {
        //遍历
        for (int i = 0, j = 0; i < str1.length(); i++) {
            while (j > 0 && str1.charAt(i) != str2.charAt(j)) {
                j = next[j-1];
            }

            if (str1.charAt(i) == str2.charAt(j)) {
                j++;
            }
            if (j == str2.length()) {  //找到了
                return i - j + 1;
            }
        }
        return -1;
    }

    //获取到一个子串的部分匹配值表
    public static int[] kmpNext(String dest) {
        //创建一个 next 数组保存部分匹配值
        int[] next = new int[dest.length()];
        next[0] = 0;  //如果字符串的长度是 1,部分匹配值就是 0
        for (int i = 1, j = 0; i < dest.length(); i++) {
            //当 dest.charAt(i) != dest.charAt(j) 我们需要从 next[j-1]获取新的 j
            //直到 dest.charAt(i) == dest.charAt(j) 满足时,才退出

            //这是 KMP算法的核心点
            while (j > 0 && dest.charAt(i) != dest.charAt(j)) {
                j = next[j-1];
            }

            //当 dest.charAt(i) == dest.charAt(j) 满足时,部分匹配值就 +1
            if (dest.charAt(i) == dest.charAt(j)) {
                j++;
            }
            next[i] = j;
        }
        return next;
    }
}

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

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

相关文章

The Llama 3 Herd of Models 第8部分语音实验部分全文

第1,2,3部分,介绍、概览、预训练 第4部分,后训练 第5部分,结果 第6部分,推理 第7部分,视觉实验 8 Speech Experiments 我们进行了实验来研究将语音功能集成到Llama 3中的组合方法,类似于我们用于视觉识别的方法。在输入端,一个编码器,连同一个适配器,被并入处理语…

低代码开发是什么意思?低代码是开发的未来吗?

在数字化转型的浪潮中&#xff0c;低代码平台是一股不可忽视的力量&#xff0c;它正在以前所未有的速度改变着软件开发的格局。低代码不仅极大地简化了开发流程&#xff0c;降低了技术门槛&#xff0c;还通过高效、灵活的特性&#xff0c;为企业和开发者带来了前所未有的创新机…

页面弹窗中英文切换

一、遇到的问题 页面右上角弹窗如下 二、解决 去掉 lang"en"即可。

SVPWM5段式7段式差异分析和关键代码基于TI F28035

SVPWM5段式7段式差异分析和关键代码基于TI F28035 5段式有一相占空比始终为0或者1 扇区判断的扇区号和实际扇区不是一一对应,直接使用,而是映射关系 扇区判断变量 7段式和5段式在基本矢量作用顺序上的差异 SVPWM算法详解(已标注重点) 来自这篇文章,但经过实际测试,发现是…

计算机和医学领域成重灾区!5本TOP刊也位列其中,请大家谨慎投稿!

【SciencePub学术】自从Hindawi一年撤稿多达一万多篇的事件以来&#xff0c;官方对期刊质量的管控就越来越严格了。更有很多学校和单位都频频更新自己的风险期刊名单&#xff0c;其中&#xff0c;Hindawi、Frontiers、MDPI甚至都被直接打包拉黑&#xff01; 更有On Hold 期刊现…

ios上音频需要点击两次才播放

问题 用H5标签audio渲染音频&#xff0c;测试PC和安卓都没有问题&#xff0c;点击一次就播放&#xff0c;并且可以在播放之前正常显示音频时长 但是在iOS系统上没有播放之前&#xff0c;不仅时长显示为0&#xff0c;并且播放还需要点击2次才正常播放 原因 debug之后发现是因为…

计算机毕业设计选题推荐-遥感影像共享系统-Java/Python项目实战

✨作者主页&#xff1a;IT毕设梦工厂✨ 个人简介&#xff1a;曾从事计算机专业培训教学&#xff0c;擅长Java、Python、微信小程序、Golang、安卓Android等项目实战。接项目定制开发、代码讲解、答辩教学、文档编写、降重等。 ☑文末获取源码☑ 精彩专栏推荐⬇⬇⬇ Java项目 Py…

GaussDB关键技术原理|高可用:两地三中心跨Region容灾

接上篇GaussDB关键技术原理|高可用&#xff1a;逻辑复制从逻辑复制方面对GaussDB的高可用能力进行了介绍&#xff0c;本篇将从两地三中心跨Region容灾方面继续解读GaussDB高可用技术。 目录 4 两地三中心跨Region容灾 4.1 概述 4.2 异地容灾部署示例 集中式 分布式&#x…

sheng的学习笔记-AI-层次聚类

AI目录&#xff1a;sheng的学习笔记-AI目录-CSDN博客 需要学习的前置知识&#xff1a;聚类&#xff0c;可参考&#xff1a;sheng的学习笔记-AI-聚类(Clustering)-CSDN博客 什么是层次聚类 层次聚类(hierarchical clustering)试图在不同层次对数据集进行划分&#xff0c;从而形…

2024年第五届华数杯全国大学生数学建模竞赛【C题】完整版代码+结果 分享

问题1的设问虽然不涉及到数学模型&#xff0c;只需要统计题目所给附件数据&#xff0c;但在做题之前可以先整理思路&#xff1a; ①统计景点评分最高分&#xff1b;②统计最高分在所有文件中出现的总次数&#xff1b;③统计出现高分次数最多的csv文件&#xff1b;④统计出现最…

js前端展示ppt【插件:PPTXJS】

前端展示PPT 使用插件&#xff1a; 官方网址: https://pptx.js.org/index.html github网址: https://github.com/meshesha/PPTXjs/releases 实例网址: https://pptx.js.org/pages/demos.html通过下载官方demo可以获得完整的实例

MySQL简介 数据库管理与表管理

文章目录 1 MySQL的优势2 MySQL数据类型1 数字类型2 日期和时间类型3 字符串类型 3 数据库管理4 数据表管理参考 1 MySQL的优势 性能优化&#xff1a;通过优化存储引擎&#xff08;InnoDB&#xff0c;MyISAM&#xff09;和查询优化。解决大规模数据处理和查询优化开源&#xf…

孩子被确诊为自闭症怎么办?

当家庭收到孩子被确诊为自闭症的消息时&#xff0c;这无疑是一次巨大的心理冲击和挑战。面对这一突如其来的诊断&#xff0c;许多家长会感到无助、焦虑甚至绝望。然而&#xff0c;重要的是要认识到&#xff0c;自闭症并非不可逾越的障碍&#xff0c;通过科学、专业的干预和治疗…

调度中心控制台:智慧运营的心脏,引领高效管理的未来

在当今这个信息化、智能化发展的时代&#xff0c;各行各业的运营管理都面临着前所未有的挑战与机遇。作为协调资源、指挥调度的核心枢纽&#xff0c;调度中心控制台不仅是信息汇聚的窗口&#xff0c;更是智慧决策与高效执行的起点。接下来就由嘉德立给大家深入探讨一下调度中心…

【C#语音文字互转】.NET的TTS文本转语音合成

本文章环境介绍&#xff1a; Visual Studio 2022&#xff1b;C#SDK为.NET6.0 一. 启动 Visual Studio 并创建控制台应用程序 1.1 首先在项目打开NuGet包管理工具下载System.Speech。 1.2测试 下面为一个典型的输出示例 using System.Speech.Synthesis; namespace KeepTalkin…

视觉SLAM第三讲

本讲将介绍视觉 SLAM 的基本问题之一&#xff1a;三维空间的刚体运动描述方式&#xff1a;旋转矩阵、变换矩阵、四元数和欧拉角。 点、向量和坐标系 点&#xff1a;空间当中的基本元素&#xff0c;没有长度&#xff0c;没有体积。 向量&#xff1a;可以将向量看作从一个点指向…

如何快速创建一个微信报名链接

在这个快节奏的时代&#xff0c;如何让活动报名更加便捷、高效&#xff0c;成为了众多主办方关注的焦点。今天&#xff0c;就让我们一起探索如何快速创建一个微信报名链接&#xff0c;让您的活动报名变得前所未有的简单与智能。 一、洞悉需求&#xff0c;解锁报名新方式 在数字…

【Pyspark-驯化】一文搞定spark的代码执行原理和使用技巧

【Pyspark-驯化】一文搞定spark的代码执行原理和使用技巧 本次修炼方法请往下查看 &#x1f308; 欢迎莅临我的个人主页 &#x1f448;这里是我工作、学习、实践 IT领域、真诚分享 踩坑集合&#xff0c;智慧小天地&#xff01; &#x1f387; 相关内容文档获取 微信公众号 &…

国标GB28181协议设备通道告警没有快照图片怎么办?实时流抓图/录像抓图

熟悉国标GB28181协议的同学都知道&#xff0c;国标协议在告警推送这一块定义了各种告警类型和告警参数&#xff0c;但就是没有定义告警的图片应该怎么上传到平台&#xff0c;所以&#xff0c;现在市面上的所有设备&#xff0c;几乎都不支持上传告警图片&#xff0c;这给我们的项…

CCRC-DSA数据安全评估师:加快构建大网络安全工作格局

7月31日&#xff0c;第十二届ISC.AI互联网安全大会开幕式在北京国家会议中心隆重举行&#xff0c;本次大会以“构建大型安全防护模型&#xff0c;引领安全产业创新”为主题。 中央网络安全和信息化委员会办公室副主任、国家互联网信息办公室副主任王京涛出席并发表了重要讲话。…