<学习笔记>KMP(MP)算法

MP算法和OMP算法及其思想 MP算法和OMP算法及其思想,优缺点,算法步骤及程序代码。 立即下载

*(ノ゚▽゚)ノ对方不想和你说话并且向你扔出了一个题。

【题目】 luogu 3375 KMP字符串匹配

题目描述

如题,给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置。

为了减少骗分的情况,接下来还要输出子串的前缀数组next。

(如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了。)

输入输出格式

输入格式:
第一行为一个字符串,即为s1(仅包含大写字母)

第二行为一个字符串,即为s2(仅包含大写字母)

输出格式:

若干行,每行包含一个整数,表示s2在s1中出现的位置

接下来1行,包括length(s2)个整数,表示前缀数组next[i]的值。

输入输出样例

输入样例#1:
ABABABC
ABA
输出样例#1:
1
3
0 0 1

说明

时空限制:1000ms,128M

数据规模:

设s1长度为N,s2长度为M

对于30%的数据:N<=15,M<=5

对于70%的数据:N<=10000,M<=100

对于100%的数据:N<=1000000,M<=1000

Ps:由于我打的字符串下标是以0为开头的,学的也是以0为开头的,将就看吧。。。

对于这个题,让我们先抛开kmp,想想可以怎么解_(:з」∠)_
首先想到的是暴力匹配。
对于s1和s2,暴力枚举每一个点并进行匹配,由于每次进行匹配时时间复杂度为O(m),至少需要扫(n-m)个点,时间复杂度近似O(nm),TLE!
优化:每次匹配时如果有不同的就直接跳过。

依旧会T…orz

那么…(ノ゚▽゚)ノ kmp…

KMP算法简介

kmp算法是一种改进的字符串匹配算法,由D.E.Knuth,J.H.Morris和V.R.Pratt同时发现,因此人们称它为克努特——莫里斯——普拉特操作(简称KMP算法)。KMP算法的关键是利用匹配失败后的信息,尽量减少模式串与主串的匹配次数以达到快速匹配的目的。具体实现就是实现一个next()函数,函数本身包含了模式串的局部匹配信息。时间复杂度O(m+n)。(摘自百度百科)

O(m): 对s2的预处理
O(n) : 扫一遍s1,完成匹配

当匹配的过程中发现s1[i]与s2[j]不同时
如 匹配到c和a发现他们不同:

这里写图片描述

暴力会把aabaabaa往后移一位重新比较。
而kmp算法会因为c之前的已经比较过,我们已经知道s1前面的部分为aabaaba了,显然后移一位不可能匹配成功,后移两位也不可能匹配成功,而后移三位是有可能的。所以kmp算法会直接后移三位后再比对c和s2的第5个字符。

由于s2已经给出,所以我们可以预先处理出当s2[i]匹配失败时转移后应继续判断的位置(s2可能能继续匹配的位置 or s2后移的位数)。 这里用fail数组表示。
如上图中的 fail[7]=4;

可以写出kmp的代码为

void Kmp()
{
    n=strlen(s1),m=strlen(s2);
    Done_fail(); 
    for(int i=0,j=0;i<n;++i) // j既可以理解为下标,也可以理解为当前已经匹配了j个字符(0开头的好处2333)
    {
        while(j&&s1[i]!=s2[j]) j=fail[j]; // 如果不匹配,就把j往前跳(s2往后移),直到j=0或可以匹配为止
        if(s1[i]==s2[j]) ++j; // 可以匹配 j++;
        if(j==m) Ans[++ans]=i-m+1,j=fail[j];  // 匹配成功,记录下出现的位置并更新j
    }
}

难点:

fail数组的处理:

递推求法:

void Done()
{
    fail[0]=fail[1]=0; 
    for(int i=1,k=0;i<m;++i)
    {
        k=fail[i]; // 已经匹配了i(0~i-1)个字符的fail值,也就是i的fail值,此时我们并不知道s2[i]是否已经/可以匹配,通过判断s2[i],我们用fail[i]来更新fail[i+1]。
        while(k&&s2[i]!=s2[k]) k=fail[k];// 如果s2[i]!=s2[k](s2[k]为s2可能能继续匹配的字符),说明s2[i+1]如果失配了,我们并不能直接转移到s2[k+1]尝试匹配。所以我们就像上面的kmp代码一样,不断往前跳,直到找到一个可以匹配的地方为止。(就如同字符串失配了一样)
        fail[i+1]=(s2[i]==s2[k])?k+1:0;
    }
}

建议自己脑跑一遍以加深理解。
栗子:

i01234567891011
s2[i]aabaabaacab无
fail[i]001012345010

网上的博客里还有另一1种理解方法,用next数组表示,统计s2”前缀”和”后缀”的最长的共有元素的长度,next[i]表示s2中前i个字符的”前缀”和”后缀”的最长的共有元素的长度,如 ABCDABBD 对应的next 为 0,0,0,0,1,2,0,0 。所以next[i-1]可以直接用作下标为i的字符失配时应转移到的位置。也就是说fail是next统一往后移了一位。其实思想是一样的。(next应该会更好懂一些)

摘自网上的next代码。

void Done_next()
{
    next[0] = 0;
    for (int i = 1,k = 0; i < m; ++i) // k为最大长度
    {
        while(k > 0 && s2[i] != s2[k])
             k = next[k-1];       
        if (s2[i] == s2[k])
        {
            k++;
        }
        next[i] = k;
    }
}

那么回到原题,发现只是个模板题,直接上代码好了(:3_ヽ)_

注:原题的字符串是以1为开头的,另外求的也是next数组

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#include<cstdlib>
using namespace std;

int n,m,ans;
int fail[1010],Ans[1000010];
char a[1000010],b[1010];

void Done()
{
    fail[0]=fail[1]=0;
    for(int i=1,k=0;i<m;++i)
    {
        while(k&&b[i]!=b[k]) k=fail[k];
        fail[i+1]=b[i]==b[k]?++k:0;
    }
}
void Kmp()
{
    n=strlen(a),m=strlen(b);
    Done();
    for(int i=0,j=0;i<n;++i)
    {
        while(j&&a[i]!=b[j]) j=fail[j];
        if(a[i]==b[j]) ++j;
        if(j==m) Ans[++ans]=i-m+1,j=fail[j];
    }
}
int main()
{
    cin>>a>>b;
    Kmp();
    //cout<<ans<<'\n';  
    for(int i=1;i<=ans;++i)
      cout<<Ans[i]+1<<'\n';  // 以一为开头
    for(int i=1;i<=m;++i)  // 往前移一位
    cout<<fail[i]<<' ';
    cout<<'\n';
    return 0;
} 

ヾノ≧∀≦)o βyё βyё..

The end.

WinCC ActiveX控件“许可证缺失”故障排查:从注册表修复到系统兼容性全解析 本文深入解析WinCC ActiveX控件报错“未找到许可证信息”的根本原因与解决方案。核心在于系统注册表中控件的设计时许可证密钥丢失或损坏。文章提供了从手动修复注册表、排查64位系统兼容性,到预防性环境部署的全流程专业指南,帮助工程师彻底解决这一常见故障。 阅读详情

相关推荐

Unity动画状态机实战:Trigger和Bool参数到底怎么选?附5个常见场景解析

本文深入解析Unity动画状态机中Trigger和Bool参数的核心差异与应用场景。通过对比两者在描述瞬时事件与持续状态上的本质区别,并结合角色移动、攻击连招、跳跃落地、受击死亡及环境交互等5个实战场景,提供了清晰的选择逻辑与避坑指南,帮助开发者构建更健壮、易维护的动画逻辑。

weixin_29009501的博客 120

KMP算法

换句话说,s2中第i位和第j位的元素是相同的,在s1和s2的匹配的移动过程中,我们可以通过将s1的某一位分别与s2的第i位、第j位对齐来完成一次移动。要使s1和s2匹配,我们的想法是,首先对s1进行遍历,在遍历过程中,判断s1和s2对应位置是否相同,如果不相同,就进行移动,让s1的当前位置与s2的next[j](j是当前s2中失配的位置)位置对齐;但是其实,每次遇到不匹配的字母,我们并不需要在s1上逐个移动,每次移动对s2的所有字符逐个判定,而是可以通过使s1和s2上某个特定的字符(串)对齐,来实现移动。

weixin_68738523的博客 436

halcon 深度学习标注_Halcon deep learning之目标检测笔记(一)

设置输入输出的路径输入路径有两个,一个是图像路径HalconImageDir,一个是Json文件路径PillBagJsonFile。这两个参数用于后续在图像路径中读取coco文件。输出路径首先定义一个新的文件夹路径,用于存放样本和模型文件等数据。设置基于深度学习的目标检测模型的路径,该模型文件以.hdl结尾。设置样本数据文件夹ExampleDataDir:'detect_pills_data'数据...

weixin_27885313的博客 2699

洛谷 P3375 KMP字符串匹配

题目描述: 给出两个字符串s1和s2,其中s2为s1的子串,求出s2在s1中所有出现的位置。 为了减少骗分的情况,接下来还要输出子串的前缀数组next。 (如果你不知道这是什么意思也不要问,去百度搜[kmp算法]学习一下就知道了。) 输入输出格式 输入格式: 第一行为一个字符串,即为s1(仅包含大写字母) 第二行为一个字符串,即为s2(仅包含大写字母) 输出格式: 若干行,每行包

ojzha的博客 457

Vue3+codemirror6实现公式(规则)编辑器

vue3+codemirror6+ts实现公式编辑器,可以插入标签、公式,也有补全提示

小阮的笔记本 5045

GEE高阶应用——如何绘制2000-2022年土地利用变化轨迹时序图

土地利用变化是指在一定时间范围内,土地利用类型和结构发生的变化。时序变化是指这种变化随时间的推移而发生的序列变化。土地利用变化轨迹的时序变化具体介绍如下:首先,土地利用变化轨迹的时序变化体现在土地利用类型的演变上。在过去的几十年里,随着人口的增加、经济的发展和城市化的推进,土地利用类型发生了显著的变化。传统的农田逐渐减少,而城市、工业、交通、居住等用地的面积不断扩大。同时,随着环境保护意识的提高,生态保护用地、森林、湿地等绿色用地的面积也在增加。

此星光明博客 1113

1455:【例题1】Oulipo

【题目描述】 给出两个字符串s1,s2 ((只有大写字母),求s1在s2 中出现多少次。 例如:s1=“ABA” ,s2=“ABAABA”,答案为2 。 【输入】 输入T 组数据,每组数据输出结果。 【输出】 如题述。 【输入样例】 3 BAPC BAPC AZA AZAAZAAZA VEEDI AVERDXIVYERDLAN 【输出样例】 1 3 0 【提示】 1≤s1 的长度 ≤104​​ ,1≤s2的长度 ≤106​ 。 字符串Hash模板题 #include <iostream> #in

lyc_lb 581

基于Gossip算法的柔性互联自治微网群分布式协调控制策略:复现代码与详细解释

摘要(149字): 本文基于Gossip算法实现了柔性互联微网群(MMG)的分布式协调控制策略仿真。研究构建了包含3个微网、10个分布式电源(DG)的MATLAB/Simulink模型,采用双层控制架构:上层通过柔性交流开关(FAS)实现微网间功率协调,下层利用Gossip算法完成DG间的边际成本一致性控制。重点开发了异步通信的Gossip算法核心函数,实现了分布式电源的自主边际成本估计与功率分配。仿真验证了系统在负荷变化和DG故障等工况下的协调控制能力,结果表明该策略能有效维持微网群的经济运行与功率平衡。

huanghm88的专栏 281

蓝桥杯--二字符串算法

二字符串算法

weixin_55939638的博客 567

RH850从0搭建Autosar开发环境【7】- Davinci Configurator之CanTp模块配置详解(上)

RH850从0搭建Autosar开发环境【7】- Davinci Configurator之CanTp模块配置详解(上)

weixin_42412049的博客 2297

LangChain从入门到精通最全教程

LangChain是一个用于构建基于大语言模型(LLM数据感知:连接外部数据源(文档、API等)智能代理:通过工具调用实现自主决策模块化设计:支持链式调用、记忆管理、提示词工程等from langchain . llms import BaseLLM class CustomLLM(BaseLLM) : def _call(self , prompt : str , ** kwargs) - > str : return f"自定义响应: {

Cachel Wood的博客 1409

【考研】串的模式匹配算法——KMP算法(含真题)

本文内容源于对《数据结构(C语言版)》(第2版)、王道讲解学习所得心得、笔记整理和总结,以便复习。【考研】《数据结构》知识点总结.pdf_考研数据结构知识点总结-其它文档类资源-优快云文库【2023考研】数据结构常考应用典型例题(含真题)_住在阳光的心里的博客-优快云博客目录前言一、基本概念二、KMP算法三、KMP算法的进一步优化四、习题。

qq_34438969的博客 8749

动态规划之【树形DP】第3课:树形DP应用案例实践2

动态规划之【树形DP】第3课:树形DP应用案例实践2

王老师青少年编程 763

【哈希】Oulipo

题目描述 给出两个串S1,S2(只有大写字母),求S1在S2中出现了多少次。例如S1=“ABA”,S2=“ABABA”,答案为 2。 输入T组数据,对每组数据输出结果。 每组数据保证strlen(S1)<=10^4,strlen(S2)<=10^6。 输入 输入T,表示T组数据接下来每行一个S1,每行一个S2。 输出 输出T行,表示每组的答案。 样例输入 3 BAPC ...

Uletay 352

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

霍尼韦尔SoftMaster使用说明

霍尼韦尔SoftMaster使用说明

字符串处理 —— 单模式匹配 —— MP 算法与 KMP 算法

【概述】 KMP 算法又称Knuth-Morris-Pratt 字符串匹配算法,是由于 D.E.Knuth、J.H.Morris 和 V.R.Pratt 三人共同研究的,用于解决字符串匹配问题。 其核心思想是利用已经部分匹配的有效信息,来保持文本串指针不回溯,通过修改模式串指针,让模式串尽量地移动到有效的位置,因此,整个 KMP 的重点就在于当模式串中某个字符与文本串不匹配时,如何移动模式串...

Alex_McAvoy的博客 1695

RU DOS版、EFI版32bit/64bit BIOS常用工具

DOS版、EFI版的RU工具,可用来查看IO、MEM、PCI、SMBIOS等资源。亲测在EFI SHELL下可用。

字符串匹配(一)—— KMP / MP

目的:判断目标串(T串)中是否含有模式串(P串)。 失配 T t0 t1 t2 …… tk tk+1 P p0 p1 p2 …… pk 由于字符串T和P第一个不相等的字符出现在位置k,所以两字符前k个字符是相等的,也说明两串在位置k处失配。 失效函数 定义:记录字符串P中各个字符之间关系的函数。 定义域:自变量 j 的取值范围是P在“失配”...

Erya Programming learning 490

STM32F407中文手册

STM32f407中文手册 本参考手册面向应用开发人员,提供有关使用 STM32F405xx/07xx、STM32F415xx/17xx、 STM32F42xxx 和 STM32F43xxx 微控制器存储器与外设的完整信息。STM32F405xx/07xx、STM32F415xx/17xx、STM32F42xxx 和 STM32F43xxx 构成一个微 控制器系列,各产品具有不同的存储器大小、封装和外设。有关订购信息以及器件的机械与电气特性,请参见数据手册。有关 ARM Cortex™-M4F 内核的信息,请参见《Cortex™-M4F 技术参考手册》。

模式串匹配——Hash、MP与KMP算法超详解

题目描述 这是一道模板题。 给定一个字符串 SSS 和一个字符串 TTT,求 SSS 在 TTT 中的出现次数。SSS 和 TTT 中的字符均为英语大写字母或小写字母。 SSS 中不同位置出现的 TTT 可重叠。 输入格式 输入共两行,分别是字符串 SSS 和字符串 TTT。 输出格式 输出一个整数,表示 TTT 在 SSS 中的出现次数。 输入样例 zyzyzyz zyz 样例输出 3 数据范围 1≤∣S∣,∣T∣≤1061 \leq |S|, |T| \leq 10^61≤∣S∣,∣T∣≤106,S

这是一篇普通的博客。 1630

KMP(MP)算法详解

Written with StackEdit. 由于优快云服务器的维护,我迫不得已地用了和优快云版本相近的StackEdit. KMP算法,是一种字符串匹配的算法。当然,我们已经学过了一两种字符串匹配算法,先来稍微回顾一下。

算法的设计与应用研究 3567

【模板算法】字符串匹配问题——MP算法+KMP算法

MP算法介绍: 字符串匹配中,如果我们选择最朴素的BF算法,即每次匹配失败就返回到该次刚开始匹配的位置,时间复杂度为O(M*N),M,N分别为匹配字符串p和被匹配字符串s的长度。这个复杂度在M和N长度都很大时是极其不方便的,所以,我们需要想办法利用现有的资料去减少匹配次数。如果我们在p[i]处匹配失败了,可以知道的是前0-i-1是匹配成功的,那么我们可以根据这个将P向后滑动,而不是将P移到最前面...

tjj1998的博客 1667

非常系统的KMP\MP算法讲解

包含KMP和MP算法的区别,解决了大白书上的问题 点击打开链接

Baoli1008的专栏 2008

kmp算法的弱化版本 mp算法

训练指南p211 int f[1000006]; // 建立失配函数 p为模板串 void getfail(char *p){ int m=strlen(p); f[0]=0;f[1]=0; for(int i=1;i<m;i++){ int j=f[i]; while(j&&p[i]!=p[j]) j=f[j]; f[i+1]=p[i]==p[j]?j+1:0; } }

熟睡的哲学家的博客 564

【模板】KMP与MP的区别(洛谷P3375)

学KMP的时候巨佬说我这写的是MP,仔细去查了查资料,才发现了区别。 洛谷这道题用KMP是解决不了的,KMP的nxt数组和MP的nxt数组略有不同。 https://www.cnblogs.com/yjiyjige/p/3263858.html 这位大佬写的过程很清楚,但是程序不是怎么看得懂,而且实际放到洛谷的题上测应该也是过不了的(应该。 直接放程序8 #include<bits/stdc...

NightRaven的博客 591

KMP算法的简单版本(MP)的浅略分析

前言关于KMP算法,网上给出了很多讲解,《算法竞赛入门经典》中也给出的详细解释,但不同地方把NEXT或FAIL数组的定义的不同,以致于众口纷纭,最终让读者晕头转向。NEXT数组的求解定义next[i]表示从P[0]到P[i-1]的相同前后缀的最长长度。递推已知:k=next[i],即P[0]…P[k-1] == P[i-k]…P[i-1]。转移:如果P[i]==P[k] ,那么显然next[i+1]

C_Lyr的博客 990

文本的精确匹配(BF,MP,KMP)

一,BF算法 暴力搜索,两重循环 二,MP算法 与BF算法不同的是,每当匹配失败,不必指针回溯,而是利用已经得到的部分匹配结果,将模式字符串滑动若干位置后,继续比较 当失配的情况发生在模式p的第j位: 1,当j=0,则让目标的指针前进一位,模式的起始比较地址回到P0 2,否则,在进行下一轮比较时,目标指针不发生回溯,仍指向失配的位置,而模式串的起始比较位置为P(f(j-1)+1) 在

不忘初心 1637

史上最透彻的KMP算法讲解

作 者:柳行刚 编 辑:李文臣 1 字符串匹配是经典的KMP算法。下面以字符串"BBC ABCDAB ABCDABCDABDE"为例,查找是否包含串"ABCDABD"? 图一 2      首先如上图,字符串"BBC ABCDAB ABCDABCDABDE"的第一个字符与搜词"ABCDABD"的第一个字符,B与A不相等,所以后移动。 图二

燕哥带你学算法 3203

【算法】KMP经典算法,你真的懂了吗?

有关KMP算法的书籍、帖子、博客铺天盖地,但是你真的能看懂?你知道为什么要有next数组,next数组到底什么意思,又该怎么求next数组,有了next数组之后又该怎样判断模式串和主串是否匹配成功?本文绝对不是讲解KMP算法最细致的一篇文章,但却是为了解决大家的疑惑而写的一篇文章。KMP的概念首先说说什么是KMP算法,说白了,就是不希望用简单的两层循环遍历两个串那样去看能否匹配成功。简单朴素的字符串

沐诩 6055
上一篇: csdn 的友链设置
下一篇: codevs 1378 选课 (树形dp)
Loi_Mapleleaf
博客等级 码龄10年 17粉丝 72原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值