KMP-子串匹配算法-关键点理解

news2025/3/28 2:30:32

1.理解next[]数组的使用与来历

2.求解next[]数组

一、kmp算法的原理

        首先观察暴力解法:假设主串为:abdxxabc,模式串为abxxabd。

暴力解法,就是对主串每个字符作为第一个字符,开始和模式串比较。

比如:从主串第一个字符a开始,比较到d发现不相等,然后从第二个字符b开始,直接不相等。以此类推,直到匹配或者到主串末尾。

           abxabc|abxabd                       ​​​​​​​abxabc|abxabd     ...       abxabc|abxabd

           abxabd                                     abxabd                ...                    abxabd

             图一                                         图二                                       图三

比较操作的时间复杂度为O(m×n)。

kmp算法在此基础上进行改进,关键点为,利用已经比较过的部分,比如图一的abxabd。

        当遇见不匹配的情况时,通过模式串的最长相等前后缀来确定下一次模式串比较的位置,并且不需要回退主串和模式串。前缀为不包含最后一个字符,包含第一个字符的子串,后缀为不包含第一个字符,保护最后一个字符的字串。

        理解:匹配过程中,不匹配的情形只有两种情况,其实也可以看成一种情况。第一种情况:第一个字符就不匹配,也就是说不匹配的字符前面没有字符。如图二。第二种情况:第n个字符不匹配,前n-1个字符匹配。如图一。

       第一种情况由于第一个字符就不匹配,所以主串直接遍历下一个字符,模式串还是第一个字符开始比较。第二种情况:如图一,abxab是匹配的,此时,我们只需要检查abxab这个字符串的最长相等前后缀的长度,最长相等前后缀为ab,长度为2。下一次我们直接比较模式串下标为2的字符x和此时主串不相等的字符c。然后重复上面的比较操作。

        关键点是理解最长相等前后缀的性质。在已经匹配的字符串中,如何最长相等前后缀为0,也即是没有相等的前后缀,那么显然,由于已经匹配的字符串在模式串中为模式串的一个前缀,而在主串中为已经遍历过的匹配的字符串的后缀,假设从i开始比较,到j不相等,主串i ~ j-1这一部分是模式串的一个前缀,因为肯定是从模式串的第一个字符开始比较的。而i - j-1这一部分如果没有相等的前后缀,那么显然不可能有和模式串匹配的部分,因为i~j-1是模式串的一个前缀,你都没有后缀等于前缀,所以主串不用回退,直接遍历下一个字符;如果有相等的前后缀,我们取最长的相等前后缀,i~j-1是模式串的一个前缀,假设最长的相等前后缀长度为2,也就是i, i+1是等于j-2, j-1,所以模式串的下一次比较的位置就是i+2,因为i~j-1也是主串的一部分,主串下一次比较的开始字符是j。

2.关键的最长相等前后缀的求解,也就是常说的next的数组。也就是前缀表。

一、暴力求解:两个指针,left,right,分别指向后缀的开始,前缀的末尾。从最长的前后缀字串开始比较,逐渐缩短,直到不相等。

二、常用解法:kmp的思路,其实求解next数组的过程中也用到了kmp的算法思想。一个指针j,表示以i-1为尾部的前缀字符串的最长相等前后缀的长度,也即是j指向最长相等前缀的下一个字符。i遍历字符串,从0开始。显然,第一个前缀,最长相等前后缀长度为0。

比如字符串abcxabxabcxx。next[]数组:next[0]:前缀a的最长相等前后缀的长度;next[1]:前缀ab的最长相等前后缀的长度;next[2]:前缀abc的最长相等前后缀的长度,....表示以i结尾的前缀字符串的最长相等前后缀的长度。

for(i = 0; i < str.size(); ++i)遍历一个一个求next[i]数组。

if (str[i] == str[j])   next[i] = ++j;

abcxabxabcxx: 假设此时i遍历到了x,j为i-1结尾的前缀字符串的最长相等前后缀长度,也就是红色部分表示的前缀字符串的最长相等前后缀长度,为2,也即是j指向最长相等前缀的下一个字符c。

其实就是next[i]是和next[i-1]有关系的。

关键是str[i] != str[j], while(j > 0 && str[i] != str[j]) j = next[j-1];其实就是把字符串0~j看成模式串,

i-j~i看成主串,因为指针j,表示以i-1为尾部的前缀字符串的最长相等前后缀的长度,也即是j指向最长相等前缀的下一个字符。i-j~i-1是等于0-j-1的。

28. 找出字符串中第一个匹配项的下标 - 力扣(LeetCode)

参考代码:

class Solution {
public:
    int strStr(string haystack, string needle) {
        //第一部分:求解next[]数组
       vector<int> next(needle.size());
        int j = 0;
        for(int i = 1; i < needle.size(); ++i){
            while(j > 0 && needle[j] != needle[i]){
                j = next[j - 1];
            }
            if(needle[i] == needle[j]){
                j++;
            }
            next[i] = j;
        }
        //第二部分:匹配文本串
        j = 0;
        for(int i = 0; i < haystack.size(); ++i){
            while(j > 0 && needle[j] != haystack[i])
                j = next[j - 1];
            
            if(haystack[i] == needle[j]){
                j++;
            }
            if(j == needle.size())
                return i - j + 1;
        }

        return -1;

    }
};

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

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

相关文章

网络原理之网络层、数据链路层

1. 网络层 1.1 IP协议 1.1.1 基本概念 主机: 配有IP地址,但是不进⾏路由控制的设备路由器: 即配有IP地址,⼜能进⾏路由控制节点: 主机和路由器的统称 1.1.2 协议头格式 说明&#xff1a; 4位版本号(version): 指定IP协议的版本,对于IPv4来说,就是4,对于IPv6来说,就是6 4位头…

版本控制器Git ,Gitee如何连接Linux Gitee和Github区别

&#x1f4d6; 示例场景 假设你和朋友在开发一个「在线笔记网站」&#xff0c;代码需要频繁修改和协作&#xff1a; 只用本地文件管理 每次修改后手动复制文件&#xff0c;命名为 v1.html、v2.html 问题&#xff1a;无法追踪具体改动内容&#xff1b;多人修改易冲突&#xff1…

【动态规划篇】91. 解码方法

91. 解码方法 题目链接&#xff1a; 91. 解码方法 题目叙述&#xff1a; 一条包含字母 A-Z 的消息通过以下映射进行了 编码 &#xff1a; “1” -> ‘A’ “2” -> ‘B’ … “25” -> ‘Y’ “26” -> ‘Z’ 然而&#xff0c;在解码已编码的消息时&#xff0c;你…

Python高级——类的知识

一、知识梳理&#xff1a; 二、货币场景搭建&#xff1a; 1&#xff09;代码展示&#xff1a; class RMB:count 0def __init__(self,yuan0,jiao0,fen0):self.__yuan yuanself.__jiao jiaoself.__fen fenRMB.count 1def __add__(self, other):temp RMB()temp.__yuan se…

resnet与densenet的比较

一、 ResNet&#xff08;残差网络&#xff09;和 DenseNet&#xff08;密集连接网络&#xff09; ResNet&#xff08;残差网络&#xff09;和 DenseNet&#xff08;密集连接网络&#xff09;都是深度学习中非常经典的卷积神经网络架构&#xff0c;它们在图像分类、目标检测等诸…

【算法day16】电话号码的字母组合

电话号码的字母组合 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 https://leetcode.cn/problems/letter-combinations…

软件工程之软件验证计划Software Verification Plan

个人主页&#xff1a;云纳星辰怀自在 座右铭&#xff1a;“所谓坚持&#xff0c;就是觉得还有希望&#xff01;” 本文为基于ISO26262软件验证计划模板&#xff0c;仅供参考。 软件验证计划&#xff0c;包括&#xff1a; 1. 软件需求验证计划 2. 软件架构设计验证计划 3. 软件单…

Spring Cloud之负载均衡之LoadBalance

目录 负载均衡 问题 步骤 现象 什么是负载均衡&#xff1f; 负载均衡的一些实现 服务端负载均衡 客户端负载均衡 使用Spring Cloud LoadBalance实现负载均衡 负载均衡策略 ​编辑 ​编辑LoadBalancer原理 服务部署 准备环境和数据 服务构建打包 启动服务 上传J…

分布式任务调度

今天我们讲讲分布式定时任务调度—ElasticJob。 一、概述 1、什么是分布式任务调度 我们可以思考⼀下下⾯业务场景的解决⽅案: 某电商平台需要每天上午10点&#xff0c;下午3点&#xff0c;晚上8点发放⼀批优惠券 某银⾏系统需要在信⽤卡到期还款⽇的前三天进⾏短信提醒 某…

架构设计的灵魂交响曲:系统设计各维度的深度解析与实战指南

引言: 系统设计的背景与重要性 在快速变化的技术环境中&#xff0c;数字化转型成为企业生存与发展的核心驱动力。系统设计能力不仅是技术团队的核心竞争力&#xff0c;也是推动业务创新和提升整体效率的关键因素。根据Gartner的研究&#xff0c;超过70%的数字化转型项目未能实…

[贪心算法]买卖股票的最佳时机 买卖股票的最佳时机Ⅱ K次取反后最大化的数组和 按身高排序 优势洗牌(田忌赛马)

1.买卖股票的最佳时机 暴力解法就是两层循环&#xff0c;找出两个差值最大的即可。 优化&#xff1a;在找最小的时候不用每次都循环一遍&#xff0c;只要在i向后走的时候&#xff0c;每次记录一下最小的值即可 class Solution { public:int maxProfit(vector<int>& p…

【 <二> 丹方改良:Spring 时代的 JavaWeb】之 Spring MVC 的核心组件:DispatcherServlet 的工作原理

<前文回顾> 点击此处查看 合集 https://blog.csdn.net/foyodesigner/category_12907601.html?fromshareblogcolumn&sharetypeblogcolumn&sharerId12907601&sharereferPC&sharesourceFoyoDesigner&sharefromfrom_link <今日更新> 一、Dispat…

第J3周:DenseNet121算法实现01(Pytorch版)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 目标 具体实现 &#xff08;一&#xff09;环境 语言环境&#xff1a;Python 3.10 编 译 器: PyCharm 框 架: Pytorch &#xff08;二&#xff09;具体步骤…

webrtc3A算法

使用ubuntu18.04 选择webrtc_audio_processing v0.3 下载地址 https://gitlab.freedesktop.org/pulseaudio/webrtc-audio-processing/-/tree/master git clone 完 编译 # Initialise into the build/ directory, for a prefixed install into the # install/ directory meson …

让“树和二叉树”埋在记忆土壤中--性质和概念

Nice to meet your! 目录 树的介绍&#xff1a; 树的创建&#xff1a; 二叉树的概念和结构&#xff1a; 二叉树的存储结构&#xff1a; 树的介绍&#xff1a; 概念和结构&#xff1a; 不知你们是否在现实中看见过分为两个叉的枯树&#xff0c;大概长这样&#xff1a; 那…

Spring Boot整合SSE实现消息推送:跨域问题解决与前后端联调实战

摘要 本文记录了一次完整的Spring Boot整合Server-Sent Events&#xff08;SSE&#xff09;实现实时消息推送的开发过程&#xff0c;重点分析前后端联调时遇到的跨域问题及解决方案。通过CrossOrigin注解的实际应用案例&#xff0c;帮助开发者快速定位和解决类似问题。 一、项…

【工具分享】vscode+deepseek的接入与使用

目录 第一章 前言 第二章 获取Deepseek APIKEY 2.1 登录与充值 2.2 创建API key 第三章 vscode接入deepseek并使用 3.1 vscode接入deepseek 3.2 vscode使用deepseek 第一章 前言 deepseek刚出来时有一段时间余额无法充值&#xff0c;导致小编没法给大家发完整的流程&…

康谋方案 | AVM合成数据仿真验证方案

随着自动驾驶技术的快速发展&#xff0c;仿真软件在开发过程中扮演着越来越重要的角色。仿真传感器与环境不仅能够加速算法验证&#xff0c;还能在安全可控的条件下进行复杂场景的重复测试。 本文将分享如何利用自动驾驶仿真软件配置仿真传感器与搭建仿真环境&#xff0c;并对…

Linux内核IPv4路由选择子系统

一、基本知识 1.具体案例&#xff1a;直连路由 结构fib_nh表示下一跳&#xff0c;包含输出网络设备、外出接口索引等信息。 有两个以太网局域网 LAN1 和 LAN2&#xff0c;其中 LAN1 包含子网 192.168.1.0/24&#xff0c;而 LAN2 包含子网 192.168.2.0/24。在这两个 LAN 之…

NWAFU 生物统计实验二 R语言版

#1 setwd(修改为你的工作路径或桌面路径) feed_types <- c("A", "B", "C") weight_gain_means <- c(36.8, 34.9, 21.3) weight_gain_sds <- c(2.4, 2.7, 6.6) weight_gain <- rnorm(3, mean weight_gain_means, sd weight_gain_sd…