KMP

前言:这把高端局

关于KMP

  • 时间复杂度为 \(O(n+m)\) 的优秀字符串查找算法。
  • 适用于在句子/文章中查找一段文字(词语)。

KMP实现

关于共同前后缀数组(PMT)

  • 说人话就是 \(next\) 数组。

  • 是什么?

    • \(next_i\) 表示下标从 \(1\) 到 \(i\) 的子串(后文中叫做 \(Orgin\) 串)中既是 \(Orgin\) 的前缀串又是 \(Orgin\) 的后缀串的字符串的最长长度。
    • 举例说明:开始时候的串为:abcab
      • 那 \(next_5=2\) ,因为存在串 \(ab\) 既是 \(Orgin\) 的前缀又是 \(Orgin\) 的后缀,而且在所有满足条件的串中,它是最长的。所以把 \(next_5\) 设为它的长度—— \(2\).
  • 构建 \(PMT\) 的详细步骤

    • 初始化:设模式串为 \(P\),长度为 \(m\),创建一个长度为 \(m\) 的数组 \(pmt\) 来存储部分匹配表(相当于 \(next\) 数组)的值。初始化 \(pmt[0] = 0\),因为模式串的第一个字符的前缀子串只有一个字符,不存在相等的前后缀。
    • 遍历模式串:从模式串的第二个字符开始遍历,即 \(i = 1\) 到 \(i = m - 1\)。对于每个位置 \(i\),设两个指针,一个指针 j 指向当前前缀子串的最长相等前后缀的下一个位置,初始时 \(j = pmt[i - 1]\)。

      -比较字符:比较 \(P[i]\) 和 \(P[j]\)。如果 \(P[i]\) 等于 \(P[j]\),说明找到了更长的相等前后缀,此时 \(pmt[i] = j + 1\),然后将 \(j\) 后移一位,即 \(j = j + 1\),继续下一个位置的比较。
    • 不相等情况:如果 \(P[i]\) 不等于 \(P[j]\),且 \(j > 0\),则将 \(j\) 更新为 \(pmt[j - 1]\),继续比较 \(P[i]\) 和 \(P[j]\)。这是因为当 \(P[i]\) 和 \(P[j]\) 不相等时,需要回溯到 \(j\) 位置之前的最长相等前后缀的下一个位置,继续进行比较。
    • 最终结果:当遍历完整个模式串后,\(pmt(next)\) 数组中存储的就是模式串的部分匹配表。
  • 示例

    • 以模式串 “ababaca” 为例:
    • 首先初始化 \(pmt[0] = 0\)。
      • 对于 \(i = 1\),即字符 “b”,其前缀子串 “a” 不存在相等前后缀,所以 \(pmt[1] = 0\)。
      • 对于 \(i = 2\),字符 “a”,前缀子串 “ab” 也不存在相等前后缀,\(pmt[2] = 0\)。
      • 对于 \(i = 3\),字符 “b”,此时前缀子串 “aba”,发现前缀 “a” 和后缀 “a” 相等,所以 \(pmt[3] = 1\)。
      • 对于 \(i = 4\),字符 “a”,前缀子串 “abab”,最长相等前后缀为 “ab”,所以 \(pmt[4] = 2\)。
      • 对于 \(i = 5\),字符 “c”,先看 \(j = pmt[4] = 2\),比较 “c”“b” 不相等,再将 \(j\) 更新为 \(pmt[2 - 1] = 0\),此时 “c”“a” 也不相等,所以 \(pmt[5] = 0\)。
      • 对于 \(i = 6\),字符 “a”,先看 \(j = pmt[5] = 0\),比较 “a”“a” 相等,所以 \(pmt[6] = 1\)。
      • 最终得到的 PMT 数组为 [0, 0, 0, 1, 2, 0, 1]
  • \(next\) 数组生成代码

#include<bits/stdc++.h>
using namespace std;
const int N = 1010, MOD = 1e9+7;
const int P = 131; int nxt[N];
int n,m,j = 0,i = 2;//Notice: i从2开始长度为0和1的串共同前后缀为零
char s[N];
int main() {
cin>>n>>s+1;
while(i <= n){
while(s[j+1] != s[i] and j != 0) j = nxt[j];
if(s[i] == s[j+1]) j++;
nxt[i] = j;
i++;
}
for(int i = 1;i <= strlen(s+1);i++){
cout<<nxt[i]<<endl;
}
return 0;
}

查找

  • 如果当前字符匹配,那就继续进行,否则就把首个模式串的位置设置为当前位置的 \(next\) 数组对应的值的下标。(咕咕咕)
#include<bits/stdc++.h>
using namespace std;
const int N = 1010, MOD = 1e9+7;
const int P = 131; char p[N], s[N]; //p=Pattern
int nxt[N];
int n, m;
/*
abacdaba
00100123 */
int main() {
scanf("%d%s%d%s", &n, p + 1, &m, s + 1);
for (int i = 2, j = 0; i <= n; i++) {
while (j and p[i] != p[j + 1]) j = nxt[j];
if (p[i] == p[j + 1]) j++;
nxt[i] = j;
}
for (int i = 1, j = 0; i <= m; i++) {
while (j != 0 and s[i] != p[j + 1]) {//不匹配就根据next移动
j = nxt[j];
}
if (s[i] == p[j + 1]) j++;
if (j == n) {
printf("%d ", i - n + 1);
j = nxt[j];
}
}
return 0;
}

问题 A: 【一本通提高篇KMP】剪花布条 P3375 【模板】KMP

解法

  • 就是板子
#include<bits/stdc++.h>
using namespace std;
const int N = 1010, MOD = 1e9+7;
const int P = 131; char p[N], s[N]; //p=Pattern
int nxt[N];
int n, m;
/*
abacdaba
00100123 */
int main() {
while (1) {
scanf("%s", s + 1);
if (s[1] == '#') return 0;
scanf("%s",p+1);
int ans = 0;
n = strlen(p + 1);
m = strlen(s + 1);
for (int i = 2, j = 0; i <= n; i++) {
while (j and p[i] != p[j + 1]) j = nxt[j];
if (p[i] == p[j + 1]) j++;
nxt[i] = j;
}
for (int i = 1, j = 0; i <= m; i++) {
while (j != 0 and s[i] != p[j + 1]) {//不匹配就根据next移动
j = nxt[j];
}
if (s[i] == p[j + 1]) j++;
if (j == n) {
ans++;
j = 0;//注意这里j为0,而KMP算法中这里是j=F[j-1]+1,因为一块花纹不能重复出现在多条小饰条上
}
}
printf("%d\n",ans);
}
return 0;
}

P4391 [BalticOI 2009]【一本通提高篇KMP】Radio Transmission(BZOJ1355)

解法

就是利用next数组的离奇关系来解决.

#include<bits/stdc++.h>
using namespace std;
const int N = 1010000, MOD = 1e9+7;
const int P = 131; char p[N], s[N]; //p=Pattern
int nxt[N];
int n, m;
/*
abacdaba
00100123 */
int main() { scanf("%d%s", &n, p + 1);
for (int i = 2, j = 0; i <= n; i++) {
while (j and p[i] != p[j + 1]) j = nxt[j];
if (p[i] == p[j + 1]) j++;
nxt[i] = j;
}
printf("%d\n", n-nxt[n]); return 0;
}

2025dsfz-KMP学习笔记的更多相关文章

  1. KMP学习笔记

    功能 字符串T,长度为n. 模板串P,长度为m.在字符串T中找到匹配点i,使得从i开始T[i]=P[0], T[i+1]=P[1], . . . , T[i+m-1]=P[m-1] KMP算法先用O( ...

  2. 扩展kmp学习笔记

    kmp没写过,扩展kmp没学过可还行. 两个愿望,一次满足 (该博客仅用于防止自己忘记,不保证初学者能看懂我在瞎bb什么qwq) 用途 对于串\(s1,s2\),可以求出\(s2\)与\(s1\)的每 ...

  3. 扩展kmp 学习笔记

    学习了一下这个较为冷门的知识,由于从日报开始看起,还是比较绕的-- 首先定义 \(Z\) 函数表示后缀 \(i\) 与整个串的 \(lcp\) 长度 一个比较好的理解于实现方式是类似于 \(manac ...

  4. 串的应用与kmp算法讲解--学习笔记

    串的应用与kmp算法讲解 1. 写作目的 平时学习总结的学习笔记,方便自己理解加深印象.同时希望可以帮到正在学习这方面知识的同学,可以相互学习.新手上路请多关照,如果问题还请不吝赐教. 2. 串的逻辑 ...

  5. 「学习笔记」字符串基础:Hash,KMP与Trie

    「学习笔记」字符串基础:Hash,KMP与Trie 点击查看目录 目录 「学习笔记」字符串基础:Hash,KMP与Trie Hash 算法 代码 KMP 算法 前置知识:\(\text{Border} ...

  6. 牛客网《BAT面试算法精品课》学习笔记

    目录 牛客网<BAT面试算法精品课>学习笔记 牛客网<BAT面试算法精品课>笔记一:排序 牛客网<BAT面试算法精品课>笔记二:字符串 牛客网<BAT面试算法 ...

  7. AC自动机板子题/AC自动机学习笔记!

    想知道484每个萌新oier在最初知道AC自动机的时候都会理解为自动AC稽什么的,,,反正我记得我当初刚知道这个东西的时候,我以为是什么神仙东西,,,(好趴虽然确实是个对菜菜灵巧比较难理解的神仙知识点 ...

  8. OI知识点|NOIP考点|省选考点|教程与学习笔记合集

    点亮技能树行动-- 本篇blog按照分类将网上写的OI知识点归纳了一下,然后会附上蒟蒻我的学习笔记或者是我认为写的不错的专题博客qwqwqwq(好吧,其实已经咕咕咕了...) 基础算法 贪心 枚举 分 ...

  9. Hash学习笔记

    啊啊啊啊,这篇博客估计是我最早的边写边学的博客了,先忌一忌. 本文章借鉴与一本通提高篇,但因为是个人的学习笔记,因此写上原创. 目录 谁TM边写边学还写这玩意? 后面又加了 Hash Hash表 更多 ...

  10. 【学习笔记】字符串—马拉车(Manacher)

    [学习笔记]字符串-马拉车(Manacher) 一:[前言] 马拉车用于求解连续回文子串问题,效率极高. 其核心思想与 \(kmp\) 类似:继承. --引自 \(yyx\) 学姐 二:[算法原理] ...

随机推荐

  1. 单用户模式启动 CentOS/RHEL 7/8 的三种方法

    单用户模式启动 CentOS/RHEL 7/8 的三种方法   单用户模式,也被称为维护模式,超级用户可以在此模式下恢复/修复系统问题. 通常情况下,这类问题在多用户环境中修复不了.系统可以启动但功能 ...

  2. FLink参数pipeline.operator-chaining介绍

    1.当使用flink提交一个任务,没有给算子设置并行度情况下,默认所有算子会chain在一起,整个DAG图只会显示一个算子,虽然有利于数据传输,提高程序性能,但是无法看到数据的输入和疏忽,业绩反压相关 ...

  3. RabbitMQ(八)——消息确认

    RabbitMQ系列 RabbitMQ(一)--简介 RabbitMQ(二)--模式类型 RabbitMQ(三)--简单模式 RabbitMQ(四)--工作队列模式 RabbitMQ(五)--发布订阅 ...

  4. 在windows主机本地快速部署使用deepseek-r1大模型

    一台配备 Windows 操作系统.12GB 或以上显存的英伟达显卡.8GB 或以上内存,并能连接互联网的电脑可以继续阅读以下内容. 简介 Ollama(用于下载和启动大模型) Ollama 专注于本 ...

  5. 程序员转型AI:行业分析

    系列目录 1.程序员转型AI:行业分析 2.程序员转型AI:转型计划 3.程序员转型AI:落地实践 4.程序员转型AI:展望未来 一.背景分析 进入2025年,AI已经爆发式增长,且进入实际商业变现阶 ...

  6. 4. MySQL 逻辑架构说明

    4. MySQL 逻辑架构说明 @ 目录 4. MySQL 逻辑架构说明 1. 逻辑架构剖析 1.1 服务器处理客户端请求 1.2 Connectors(连接器) 1.3 第1层:连接层 1.4 第2 ...

  7. openEuler 24.03 SP1下载clang-18的办法(RISC-V版)

      距离openEuler 24.03 SP1发版已经过去了一段时间了,值得注意的是,在这个新的发行版中,可以直接通过命令行下载clang18了!之前的发行版中clang的版本是17,可以直接dnf ...

  8. Go红队开发—并发编程

    目录 并发编程 go协程 chan通道 无缓冲通道 有缓冲通道 创建⽆缓冲和缓冲通道 等协程 sync.WaitGroup同步 Runtime包 Gosched() Goexit() 区别 同步变量 ...

  9. PHP测试代码执行时间

    https://blog.csdn.net/wyqwclsn/article/details/39930125 非常简单代码开始前加一个$start = microtime(true);代码结束后加一 ...

  10. C#/.NET/.NET Core优秀项目和框架2025年2月简报

    前言 公众号每月定期推广和分享的C#/.NET/.NET Core优秀项目和框架(每周至少会推荐两个优秀的项目和框架当然节假日除外),公众号推文中有项目和框架的详细介绍.功能特点.使用方式以及部分功能 ...