学习报告:kmp

article/2025/10/9 7:38:45

我们应该都知道一个这样子的题目,

输入两个字符串,求一个字符串在另一个字符串出现的次数,我们可以使用两个for循环来解决这个事,可是这个方法的时间要太久了,所以就需要我们kmp,我们先来介绍一个表

这个表的原理就是我们可以通过他找到上一次出现的下标,首先我们看这个字符串

将它拆成这样子,就是a,ab~~~这样子我画图不太行,不过我相信聪明的你肯定看的懂

然后我们找每一个的最长相等的前后缀,将他和数组下标一一对应,不得不说他们画的真好

这样子我们就可以得到每个下标的前后缀,然后就是我们最后那个数不要,然后一个下标对于一个数,就像这样子

然后,我们再去找一一对应的关系

当我们没有对于上的时候,我们就将j(p的下标)到我们刚刚那个表也就是最下面那个数字的下标,j=1,然后再进行对比,这样子,我们的对应速度就会快很多,有可能这个不明显那我们换成

用上面这个方法是不是快多了!这些就是kmp的思想,那我们要怎么代码实现呢,首先我们要把那个表搞出来,这个表搞出来,这个有一步:

      else{if(len>0){len=table[len-1];}else{next[i]=table[i]=len;i++;}}

这一步我也不太懂,可以看看这个大佬讲的

【KMP字符串匹配算法2】

https://www.bilibili.com/video/BV1hW411a7ys?vd_source=c9016f395efdf6f1094ae706e81044e3

void table1(char arr[],int n)
{int i,len;n=strlen(arr);next[i]=table[0]=0;//table表示表len=0;//用来记录我们的表中的数i=1;while(i<n){if(arr[i]==arr[len]){len++;next[i]=table[i]=len;i++;}else{if(len>0){len=table[len-1];}else{next[i]=table[i]=len;i++;}}}
}

然后我们找出来这个表,把他往后移一位,将第一个数改成-1,这样子方便我们下面判断,你要是要改为666也没关系,你只能祈祷数据不会加到666去

void movetable(int n)
{int i;for(i=n-1;i>0;i--){table[i]=table[i-1];}table[0]=-1;
}

做完上面准备步骤,下面就是找相同啦

void zhao(char arr[],char brr[])
{int i,j,n,m;//brr为子串,arr为主串n=strlen(brr);//brr的jm=strlen(arr);//arr的ii=j=0;table1(brr,n);movetable(n);while(i<m){if(j==n-1&&arr[i]==brr[j]){printf("%d\n",i-j+1);j=table[j];//这步就是我们可以如果ababa  aba你要是直接等于0就错了,我们要回到上一次出现的地方,然后继续找}if(arr[i]==brr[j]){i++;j++;}else{j=table[j];//不相等我们就让brr下标的移到他上一次出现的地方if(j==-1)//找到最后啦,就说明找不到,找不到就拉到,重新开始找呗{i++;j++; }}}
}

这上面就是kmp的算法思想以及我们的代码实现,写个题目吧

复制Markdown 展开

题目描述

给出两个字符串 s_1s1 和 s_2s2,若 s_1s1 的区间 [l, r][l,r] 子串与 s_2s2 完全相同,则称 s_2s2 在 s_1s1 中出现了,其出现位置为 ll

现在请你求出 s_2s2 在 s_1s1 中所有出现的位置。

定义一个字符串 ss 的 border 为 ss 的一个非 ss 本身的子串 tt,满足 tt 既是 ss 的前缀,又是 ss 的后缀。

对于 s_2s2,你还需要求出对于其每个前缀 s's′ 的最长 border t't′ 的长度。

输入格式

第一行为一个字符串,即为 s_1s1。

第二行为一个字符串,即为 s_2s2。

输出格式

首先输出若干行,每行一个整数,按从小到大的顺序输出 s_2s2 在 s_1s1 中出现的位置。

最后一行输出 |s_2|∣s2∣ 个整数,第 ii 个整数表示 s_2s2 的长度为 ii 的前缀的最长 border 长度。

输入输出样例

输入 #1复制

ABABABC

ABA

输出 #1复制

1

3

0 0 1

说明/提示

样例 1 解释

对于 s_2s2 长度为 33 的前缀 ABA,字符串 A 既是其后缀也是其前缀,且是最长的,因此最长 border 长度为 11。

数据规模与约定

本题采用多测试点捆绑测试,共有 3 个子任务

  • Subtask 1(30 points):|s_1| \leq 15∣s1∣≤15,|s_2| \leq 5∣s2∣≤5。

  • Subtask 2(40 points):|s_1| \leq 10^4∣s1∣≤104,|s_2| \leq 10^2∣s2∣≤102。

  • Subtask 3(30 points):无特殊约定。

对于全部的测试点,保证 1 \leq |s_1|,|s_2| \leq 10^61≤∣s1∣,∣s2∣≤106,s_1, s_2s1,s2 中均只含大写英文字母。

这个题目简简单单,没什么好说的就是我们找出他的位置,然后还要输出一下表格,注意一下,我们找的表格不是移动后的是移动前的,所以我们就再加个表格记录一下呗,值得注意的是这个数组一定一定要大!!!要不然得不到100!!!

#include <stdio.h>
#include <string.h>
#define MAXN 1000010
int table[MAXN];
int next[MAXN];
char arr[MAXN];
char brr[MAXN];
void table1(char arr[],int n)
{int i,len;n=strlen(arr);next[i]=table[0]=0;//table表示表len=0;//用来记录我们的表中的数i=1;while(i<n){if(arr[i]==arr[len]){len++;next[i]=table[i]=len;i++;}else{if(len>0){len=table[len-1];}else{next[i]=table[i]=len;i++;}}}
}void movetable(int n)
{int i;for(i=n-1;i>0;i--){table[i]=table[i-1];}table[0]=-1;
}void zhao(char arr[],char brr[])
{int i,j,n,m;//brr为子串,arr为主串n=strlen(brr);//brr的jm=strlen(arr);//arr的ii=j=0;table1(brr,n);movetable(n);while(i<m){if(j==n-1&&arr[i]==brr[j]){printf("%d\n",i-j+1);j=table[j];//这步就是我们可以如果ababa  aba你要是直接等于0就错了,我们要回到上一次出现的地方,然后继续找}if(arr[i]==brr[j]){i++;j++;}else{j=table[j];//不相等我们就让brr下标的移到他上一次出现的地方if(j==-1)//找到最后啦,就说明找不到,找不到就拉到,重新开始找呗{i++;j++; }}}
}int main()
{scanf("%s",arr);scanf("%s",brr);zhao(arr,brr);int n=strlen(brr);for(int i=0;i<n;i++){printf("%d ",next[i]);}return 0;
}

下班!明天学另一个,加油加油加油!


http://chatgpt.dhexx.cn/article/2odjiA4x.shtml

相关文章

图解+原理推导完全读懂KPM算法

文章目录 串定长顺序存储方式串的模式匹配BF算法KMP算法KMP算法原理KMP算法实现求模式串T的next值算法 时间复杂度分析BF算法分析KMP算法分析KMP算法与BF算法比较 串定长顺序存储方式 我们显式地在串的索引为0处存储串长。 #define MAXSTRLEN 255 // 用户可在255以内定义最…

英文打字速度180kpm

刚测了一下打字&#xff1b; 基本在180kpm左右&#xff1b; 作为程序员应该足够用了&#xff1b; 我看了一下kpm的意思&#xff1b; 请问英文的打字速度的KPM要多少才是一般录入员的速度呢?我177KPM是高还是低呀??? - ...... 一分钟要打60个字以上,大约要打420kpm,你的17…

4. 串的【朴素模式匹配算法】、【KPM算法:求next数组、nextval数组】

串的模式匹配:在主串中,找到与模式串相同的子串,并返回其所在位置。 其实就是给出一个串abc,找到abc在主串的位置【abc都要匹配】 模式串:给出一个串abc 子串:主串中的abc【可能没有】 文章目录 1. 串的朴素模式匹配算法1.1 方法一:用k记录位置1.2 方法二:不用k2. KPM算…

KPM算法详解(Next数组)

由LeetCode_28引发的思考 最开始用了剪枝思想的朴素解法虽然做出来了&#xff0c;在看答案的时候发现了有一种叫KMP的算法专门就是解决快速查找匹配串问题的&#xff0c;进行了深入的学习。 下面的图源自宫水三叶的解答 我们有两个字符串&#xff0c;在原串中寻找是否有匹配串。…

【C#】KPM算法解决字符串匹配问题

KPM算法解决字符串匹配问题 什么是KPM算法步骤Ⅰ根据《最大长度表》部分匹配表&#xff08;next&#xff09;寻找最长前缀后缀 Ⅱ 根据 部分匹配表 进行匹配 代码实现 什么是KPM算法 Knuth-Morris-Pratt 字符串查找算法&#xff0c;简称为 “KMP算法”&#xff0c;常用于在一个…

串的匹配 (KPM算法由来引导)

前言: 引入 KPM 算法的前提是 , B-F算法中,匹配失败后不必完全从头再来 , 找到可以利用的信息 , 可以进行跳跃性匹配 下面 , 我们对字符串匹配的一些思路进行剖析: 开始匹配的操作 ,我们会让 目标串 s , 和 模式串进行对齐,就像如图所示: 我们当然是从串 t 的头结点开始对比 对…

KPM匹配算法

KPM匹配算法 不管在工作中还是学习中经常会遇到串的模式匹配&#xff0c;一般来说&#xff0c;串的模式匹配算法主要是两种【朴素模式匹配和KPM模式匹配】一种改良【KPM的改良】&#xff0c;下面先看一下朴素模式匹配&#xff1a;朴素模式匹配主要思想比较简单也比较粗暴&…

KPM算法

算法 字符串匹配之朴素算法和KMP算法及JAVA代码实现 2017年06月02日 10:31:12 阅读数&#xff1a;941 暴力匹配算法 假设现在我们面临这样一个问题&#xff1a;有一个文本串S&#xff0c;和一个模式串P&#xff0c;现在要查找P在S中的位置&#xff0c;怎么查找呢&#xff1…

Python KPM算法

知识点说明&#xff1a; 先说前缀&#xff0c;和后缀吧 比如有一个串&#xff1a;abab 则在下标为3处的&#xff08;前缀和后缀都要比下标出的长度小1&#xff0c;此处下标为3出的长度是4&#xff09; 前缀为&#xff1a;a,ab,aba 后缀为&#xff1a;b,ba,bab 一、要获取…

KPM算法——数据结构|复习局|串|复杂模式匹配算法|二维数组解决KPM

数据结构复习局——KPM算法 何为KPM&#xff1f;事先规则状态匹配dp——状态转移图状态X获得dp数组值看看图再理解下 写在前面&#xff1a; 本文仅为作者个人学习记录&#xff0c;详细具体内容参考自知乎大佬labuladong &#x1f448;点击与大佬&#x1f93a;击剑&#x1f93a;…

KMP算法原理及实例

KMP是为了解决串的匹配问题。 一、基础知识 1、概念 1.串的匹配问题&#xff1a;就是在一个长的主串s中找到另一个的短的子串t。 2.目标串&#xff08;主串\文本串&#xff09;&#xff1a;被匹配的母串&#xff0c;串s被称为目标串。 3.模式串(子串&#xff09;&#xff1a…

KPM算法思想及实现

一、比较暴力算法和KMP算法 1、暴力算法&#xff1a; 双指针遍历主串和子串&#xff0c;当发现主串和子串不匹配时&#xff0c;双指针同时回溯 2、KMP算法&#xff1a; 双指针遍历主串和子串&#xff0c;当发现主串和子串不匹配时&#xff0c;通过比较子串的next数组只回溯…

正定矩阵的性质

正定矩阵的定义&#xff1a;若矩阵A是n阶方阵&#xff0c;并且它的二次型大于0&#xff0c;即&#xff0c;则矩阵A是正定矩阵。 正定矩阵的性质&#xff1a; 正定矩阵的所有特征值都为正数。正定矩阵行列式为正数两个正定矩阵的和为正定矩阵&#xff08;两个正定矩阵的乘积不…

顺序主子式

设A为 阶矩阵&#xff0c;子式 称为A的i阶顺序主子式。 [1] 对于 阶的矩阵A&#xff0c;其共有n阶顺序主子式&#xff0c;即矩阵A的顺序主子式由 共n个行列式按顺序排列而成。

【矩阵论笔记】平方根分解

定义 例子 首先判断顺序主子式。 R矩阵每一行除以对角元 平方根分解推导 因为A的分解是唯一的&#xff0c;可以得到 L R T LR^{T} LRT 例题 待定系数法

MATLAB_数值计算_用平方根法解线性方程组—(Cholesky分解)

利用对称正定矩阵的乔累斯基分解求解对称正定方程组的方法称为平方根法对称正定矩阵A的对角元为正实对称矩阵A正定的充要条件是A的所有特征值为正对称正定矩阵非奇异&#xff0c;其逆亦为对称正定矩阵实对称矩阵A正定的充要条件是A的所有顺序主子式为正正定矩阵的顺序主子阵是正…

正定与半正定矩阵,判别的方法不能混用,否则出错

坑&#xff1a;特征值有0可以知道该矩阵不可能正定&#xff0c;那可以用顺序主子式判断是否为半正定吗&#xff1f; 答案&#xff1a;不能 例子&#xff1a;A,特征值为一个0&#xff0c;两个正数>那就是半正定啦呀 但是&#xff0c;主子式二阶小于0那就不正定了呀两种方法…

线性代数【11】二次型

前言&#xff1a; 矩阵表达的是线性关系的方程组&#xff0c;但是&#xff0c;客官世界&#xff0c;是包括稍微复杂的&#xff0c;二次方程。 尤其几何中&#xff0c;有二次曲线&#xff0c;二次型&#xff0c;就是一个多元函数&#xff0c;是多个变量的二次&#xff0c;齐次…

Lyapunov稳定性分析1(正定函数、二次型正定判定)

一、 正定函数 1.1 定义&#xff1a; 令V(x)是向量x的标量函数&#xff0c;S是x空间包含原点的封闭有限区域。如果对于S中的所有x&#xff0c;都有&#xff1a; 则V(x)是正定的&#xff08;半正定&#xff09;。正定函数更直观的描述如下图所示&#xff1a; 如果条件(3&a…

牛顿法为什么要保证Hessian矩阵正定

牛顿法为什么要保证Hessian矩阵正定&#xff1a; 实际中&#xff0c;需要求出Hessian的逆矩阵&#xff0c;只有正定矩阵&#xff0c;才可以求出逆矩阵。 正定矩阵&#xff1a;特征值全大于0&#xff1b;各阶主子式全大于0.