数据结构面试常见问题之串的模式匹配(KMP算法)系列-大师改进实现以及原理

😀前言
KMP算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt提出的,因此人们称它为克努特—莫里斯—普拉特操作(简称KMP算法)。KMP算法的核心是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。

🏠个人主页:尘觉主页

文章目录

  • 数据结构面试常见问题之串的模式匹配(KMP算法)系列-大师改进实现以及原理
    • KMP-3. KMP 算法实现
      • KMP算法实现
    • KMP-4. BuildMatch 的实现原理
    • KMP-5. BuildMatch的编程实现
    • 😄总结

数据结构面试常见问题之串的模式匹配(KMP算法)系列-大师改进实现以及原理

KMP-3. KMP 算法实现

#include<stdio.h>
#include<string.h>
typedef int Position;//Position对应的是一个整型变量,指的是数组的下标
#define NotFound -1//NotFound就应该定义成一个不可能是数组下标的东西
int main()
{
	char string[] = "This is a simple example.";//默认指字符串,但这个串可以是任何类型的
	char pattern[] = "simple";
	Position p = KMP(string,pattern);//返回的是一个字符指针的话就只能处理字符串,如果返回的是数组下标的话那可以处理任何字符的串
	if (p == NotFound ) printf("Not Found.\n");
	else printf("%s\n",string+p);//因为这里返回的是整数,这个整数就没办法被当作字符串的头指针了。如果我们要打印整个字符串的话,我们这里就只能写成string+p这样的形式
	return 0;
}

KMP算法实现

在这里插入图片描述
一直走到指针不匹配
在这里插入图片描述


Position KMP(char *string, char *pattern) {
    int n = strlen(string);//strlen得到string的长度,下方也是一样 复杂度:O(n)
    int m = strlen(pattern);//复杂度:O(m)
    int s, p,*match;//声明两个指针
    if (n < m) return NotFound;//找的n不可能比m短
    match = (int *) malloc(sizeof(int) * m);
    BuildMatch(pattern, match);//Tm = O(?)
    s = p = 0;
    while (s < n && p < m) { //当这两个指针一起往前飞,任何一个指针先指到自己指的串的末尾的时候结
        束,复杂度O(n)
        if (string[s] == pattern[p]) {
            s++;
            p++;
        }//p有时候加加有时候回退,但s永远加加
        else if (p > 0) p = match[p - 1] + 1;//为了防止得到段错误,这里加上条件p>0
        //如果p = 0的话,意味着pattern从第一个字符就不匹配,这个时候p不动,s向前走一格
        else s++;//当string[s] == pattern[p]不匹配,我们s++,继续下一轮匹配
    }
    //在我们跳出while循环的时候,p指针已经碰到pattern的末尾(p==m),那就是完全的匹配上了
    //反之p还没有到结尾,而string已经到p的结尾了,就意味着我们找不到这个模式
    return (p == m) ? (s - m) : NotFound;
}

在这里插入图片描述
KMP的整体时间复杂度:T = O(n+m+Tm)

KMP-4. BuildMatch 的实现原理

在这里插入图片描述
如果采用这种方法实现的话,时间复杂度将会达到Tm = O(m³)

新想法:如果我们要算j的match值的话先考虑他跟j-1的match值有什么关系

假如我们这是从0到j-1的字段

在这里插入图片描述

match[j] >= match[j-1] + 1(是否正确?)

如果 match[j-1]+1 这个位置上的字符与 j 位置上的字符相等,match[j] 会有可能比 match[j-1]+1 更大吗?没可能
在这里插入图片描述

match[j] = match[j-1] + 1 (最多持平啦,利用反证法证明)
且能得到这个结果的前提是运行很好在这里插入图片描述

当 pattern[match[j-1]+1] != pattern[j] 时,下一个待与 pattern[j] 比较的元素下标是:match[match[j-1]]+1
在这里插入图片描述

KMP-5. BuildMatch的编程实现

void BuildMatch(char *pattern,int *match)
{
    int i,j;
    int m = strlen(pattern);//复杂度O(m)
    match[0] = -1;
    for(j=1;j<m;j++){//复杂度O(m)
        i = match[j-1];//把这个值存入i里面,后面就可以直接用i来表示,不至于显得很长很啰嗦,怎么感觉像数学的换元法啊哈哈
        while((i>=0) && (pattern[i+1] != pattern[j]))//每次都考虑最坏情况的话复杂度可能就为O(j)了,每次都退到底的话
                i = match[i];//让i做了一个回退,回退到while条件两者有其中之一不发生的时候
        if(pattern[i+1]==pattern[j])
            match[j] = i+1;//i回退总次数不会超过i增加的总次数
        else match[j] = -1;
    }
}

整个算法复杂度:在这里插入图片描述
第一篇–>数据结构面试常见问题之串的模式匹配(KMP算法)系列-简单解决方案

第二篇–>数据结构面试常见问题之串的模式匹配(KMP算法)系列-大师改进

😄总结

KMP算法的核心思想是利用部分匹配表来记录模式串中每个字符之前部分匹配的最大长度。在匹配过程中,如果主串和模式串的某个字符不匹配,则可以根据部分匹配表直接跳转到模式串中下一个可能匹配的位置,从而避免重复比较。

BuildMatch函数用于计算模式串的部分匹配表。该函数的核心思想是利用前缀和后缀的匹配关系来计算部分匹配表。

KMP算法具有广泛的应用,例如文本编辑、生物信息学、数据挖掘等。

😁热门专栏推荐
想学习vue的可以看看这个

java基础合集

数据库合集

redis合集

nginx合集

linux合集

手写机制

微服务组件

spring_尘觉

springMVC

mybits

等等等还有许多优秀的合集在主页等着大家的光顾感谢大家的支持

🤔欢迎大家加入我的社区 尘觉社区

文章到这里就结束了,如果有什么疑问的地方请指出,诸佬们一起来评论区一起讨论😁
希望能和诸佬们一起努力,今后我们一起观看感谢您的阅读🍻
如果帮助到您不妨3连支持一下,创造不易您们的支持是我的动力🤞

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

CentOS7配置静态ip

CentOS7进入root账户,点击右上角 点击有线设置 点击有线设置,查看目前ip地址,记住,点击ipv4 点击手动,在下面的地址写你自己想要的IP地址,注意只有最后的100可以改,146改成你自己的网段,网关和DNS最后一位都写2就行了 注意DNS一定要写,要不然让他自动找不到,会断网 在这个位置…

云计算安全分析

目录 一、概述 二、《云计算服务安全指南》的云安全风险分析 2.1 客户对数据和业务系统的控制能力减弱 2.2 客户与云服务商之间的责任难以界定 2.3 可能产生司法管辖权问题 2.4 数据所有权保障面临风险 2.5 数据保护更加困难 2.6 数据残留 2.7 容易产生对云服务商的过度…

手撕算法-删除链表的倒数第 N 个结点

描述 思路 快慢指针&#xff0c;快指针先走N步&#xff0c;走不够N步返回空。慢指针和快指针一起走&#xff0c;当快指针到达终点&#xff0c;即快指针为null时&#xff0c;慢指针到达倒数第N个节点。因为要删除倒数第N个&#xff0c;所以要记录之前的节点pre&#xff0c;假设…

JavaScript原型、原型对象、原型链系列详解(二)

(二)、JavaScript原型对象 原型对象 JavaScript 的原型机制是一种非常强大和灵活的面向对象编程概念&#xff0c;它使用一个对象作为另一个对象的模板&#xff0c;从而实现继承。在 JavaScript 中&#xff0c;每个对象都有一个原型对象&#xff0c;它定义了该对象的属性和方法&…

力扣100热题[哈希]:最长连续序列

原题&#xff1a;128. 最长连续序列 题解&#xff1a; 官方题解&#xff1a;. - 力扣&#xff08;LeetCode&#xff09;题解&#xff0c;最长连续序列 &#xff1a;哈希表 官方解题思路是先去重&#xff0c;然后判断模板长度的数值是否存在&#xff0c;存在就刷新&#xff0c…

【4XVR】win11局域网共享3D影片给quest3

准备工作 首先要有一个路由器&#xff0c;使电脑和quest3处于同一个局域网下 一.创建一个离线账户 打开设置选择账户 添加账户 二.共享文件 选择要共享的文件夹&#xff0c;右键打开属性&#xff0c;点击共享 选择刚刚创建的用户&#xff0c;点击共享即可 三.使用quest观影 …

AttributeError: ‘_MSDataLoaderIter‘ object has no attribute ‘_put_indices‘

问题描述 复现代码过程中遇到错误&#xff1a;AttributeError: _MSDataLoaderIter object has no attribute _put_indices 解决方案 出错的原因是代码中使用了不存在的属性"_put_indices"。这个错误可能与你使用的版本不兼容有关。在pytorch1.x版本中&#xff0c;&q…

Unity基础框架

公共模块 单例基类 如果有很多个这样的单例模式对象,创建他们时都要重复的写单例模式代码。那么能不能利用泛型来减少这部分重复的工作量呢。 单例模式基类,最简单的写法 继承MonoBehaviour的单例基类 所以需要做一些改进 获取单例时如果为空,创建一个名字一样的物体,挂…

力扣HOT100 - 283. 移动零

解题思路&#xff1a; 双指针 指针 i 用于寻找不为零的位置 指针 j 用于寻找为零的位置 不为零时&#xff0c;自己与自己交换&#xff0c;i 和 j 同时向下一个位置移动 为零时&#xff0c;nums[ i ]与nums[ j ]交换&#xff0c;使零向后移动 class Solution {public void…

YOLOv8 | 注意力机制 | 添加ResBlock_CBAM注意力机制——论文必备(全网独家)

⭐欢迎大家订阅我的专栏一起学习⭐ 🚀🚀🚀订阅专栏,更新及时查看不迷路🚀🚀🚀 YOLOv5涨点专栏:http://t.csdnimg.cn/96Cv5 YOLOv8涨点专栏:http://t.csdnimg.cn/hmCtL YOLOv7专栏:http://t.csdnimg.cn/lA95R 💡魔改网络、复现论文、优化创新💡

python学习9:python的代码中的数据类型转换

python中数据类型的转换 1.为什么需要转换类型呢&#xff1f; 数据类型之间&#xff0c;在特定的场景下&#xff0c;是可以相互转换的&#xff0c;如字符串转数字&#xff0c;数字转字符串等&#xff1b;数据类型转换&#xff0c;在以后是我们经常使用到的功能&#xff0c;例如…

js工具方法记录

校验数字是否有效的11位手机号 function isValidPhoneNum(value: string) {return /^[1][3,4,5,6,7,8,9][0-9]{9}$/.test(value) }手机号中间4位掩码 function maskPhoneNum(phone: string, space false) {if (!phone) {return }const reg /(\d{3})\d{4}(\d{4})/return pho…

Linux常用命令和基础命令合集---非常推荐

非常好用的Linux通用基础常用命令和高级命令。 下载链接&#xff1a;https://download.csdn.net/download/lishihuijava/89026399

Python Flask 将数据传递给前端

from flask import Flask, render_templateapp Flask(__name__)app.route("/index") def index():data {name: "张三","age": 18,}return render_template("index2.html", datadata)if __name__ __main__:app.run()<!DOCTYPE ht…

OD C卷 - 分披萨

分披萨 有大小不同的奇数块披萨&#xff1b;从A开始轮流取披萨&#xff0c;第一块可以任意选取&#xff0c;其他都必须从缺口开始选&#xff1b;B每次都选最大块的&#xff0c; A知道B的想法&#xff1b;求A能获得的披萨块总和的最大值&#xff1b; 输入描述&#xff1a; 第一…

企业微信变更主体公证怎么弄?

企业微信变更主体有什么作用&#xff1f;现在很多公司都用企业微信来加客户&#xff0c;有时候辛辛苦苦积累了很多客户&#xff0c;但是公司却因为各种各样的原因需要注销&#xff0c;那么就需要通过企业微信变更主体的方法&#xff0c;把企业微信绑定的公司更改为最新的。企业…

Prometheus+Grafana 监控Tongweb嵌入式(by lqw)

文章目录 1.思路2.部署准备3.Grafana仪表盘json文件下载4.tw嵌入式jar包本地引入依赖并测试运行5.运行jmx_prometheus_javaagent-0.19.0.jar形式获取监控数据&#xff08;方法一&#xff09;6.使用Actuator 获取监听数据&#xff08;方法二&#xff09;7.Prometheus部署8.Prome…

【Nebula笔记】简介及安装

目录 一、简介 (一) 什么是图数据库 二、安装 (一) 原生安装 (二) Docker & Docker compose 1. Docker安装 Linux Window 2. 部署NebulaGraph (三) to MAC 三、Nebula Graph Studio (一) 版本兼容性 (二) 原生安装 (三) Docker compose (四) 连接Nebula Gra…

Docker(二):Docker常用命令

docker 查看docker支持的所有命令和参数。 ➜ ~ docker Management Commands:config Manage Docker configscontainer Manage containersimage Manage imagesnetwork Manage networksnode Manage Swarm nodesplugin Manage pluginssecret …

STM32之HAL开发——HAL库框架介绍

HAL库外设设计思想 HAL库借鉴面向对象的设计思想&#xff0c;将外设驱动封装为对象。 HAL库使用主线 HAL使用的主要用在俩个地方&#xff0c;无外乎外设初始化以及外设的使用。想用好这两个功能&#xff0c;我们首先得对外设的封装有一定的了解。 句柄结构体 xx_HandleTypeDef…