[kmp+模板] kmp模板

本文深入讲解KMP算法,包括ne数组的含义及其求解过程,并给出详细的KMP匹配过程实现代码。
部署运行你感兴趣的模型镜像

文章目录

0. 前言

Biu

kmp 模式匹配算法很牛,一般结合 kmp 的题目都不怎么简单,或是困难题目可以采用 kmp 的思想很快搞定,之前博文有写过 kmp· 算法原理,和简单实现了下,但是由于当时认识浅薄,大家看看就好。在此总结一个简单的 kmp 算法模板。

当时的博文:[杂谈] 12. BF、KMP、RK Algorithm 字符串匹配算法

1. kmp

在这里插入图片描述

ne 数组的含义 : ne数组用来存模式串中每个前缀最长的能匹配前缀子串的结尾字符的下标

ne[i] = j 表示下标以 i-j 为起点,i 为终点的后缀和下标以 0 为起点,j 为终点的前缀相等,且此字符串的长度最长。用符号表示为p[0~j] == p[i-j~i]

ne 数组的求取是一个自己匹配自己的过程,建议找个视屏教程或者手动模拟样例。

板子注意点:

  • 每次是拿 ij+1 所在字符判断是否匹配的
  • for 循环 i,j 的初始化情况,对应着两种初始化边界
  • 匹配成功时,假装失配,再次跳 ne 数组

模板代码:

#include <iostream>

using namespace std;

const int N = 1e5+5, M = 1e6+5;

int n, m;
char s[N], p[M];
int ne[N];

int main() {
    cin >> n >> p + 1 >> m >> s + 1;
    
    // 求ne数组过程,其实就是自己匹配自己的过程
    for (int i = 2, j = 0; i <= n; ++i) {       // ne[1]为0,即如果第一个字母失败了,则只能从头开始了
        while (j && p[i] != p[j + 1]) j = ne[j];    // 未匹配,跳ne
        if (p[i] == p[j + 1]) j ++;     // 匹配成功看下一位
        ne[i] = j;      // 表示下标以i-j为起点,i为终点的后缀和下标以0为起点,j为终点的前缀相等
    }
    
    // kmp匹配过程,每次是p[j+1]与s[i]进行匹配
    for (int i = 1, j = 0; i<= m; ++i) {
        while (j && s[i] != p[j + 1]) j = ne[j];    // j没有退回起点,失配跳ne[j]
        if (s[i] == p[j + 1]) ++j;      // 可以匹配,则j后移一位
        if (j == n) {                   // 匹配成功,长度就是m
            cout << i - n << ' ';
            // 匹配成功,即j已经走到了头,下一次匹配的时候,j往后移动的位置就是,j=ne[j]更新下j的位置就行了
            j = ne[j];  
        }
    }
    return 0;
}

您可能感兴趣的与本文相关的镜像

ACE-Step

ACE-Step

音乐合成
ACE-Step

ACE-Step是由中国团队阶跃星辰(StepFun)与ACE Studio联手打造的开源音乐生成模型。 它拥有3.5B参数量,支持快速高质量生成、强可控性和易于拓展的特点。 最厉害的是,它可以生成多种语言的歌曲,包括但不限于中文、英文、日文等19种语言

<think>首先,用户要求是关于KMP算法的代码模板。我需要根据系统级指令和用户的查询来构建响应。系统指令指定了格式:行内数学表达式用$...$,独立公式用$$...$$,使用LaTeX语法正确,用中文回答,生成相关问题,并在引用的段落末尾添加引用标识。 用户供了三个引用:[1]、[2]、[3],都涉及KMP算法的描述和代码模板。我需要参考这些来回答用户的问题:"我想查找KMP算法的代码模板 请问KMP算法代码模板"。 用户的上一个问题或上下文是:"参考站内引用:引用[1]:...引用[2]:...引用[3]:...",然后说"我想查找KMP算法的代码模板 请问KMP算法代码模板"。所以,核心是KMP算法的代码模板。 我的响应需要: 1. 结构清晰。 2. 使用中文。 3. 包含代码模板。 4. 生成相关问题。 5. 在引用段落末尾添加引用标识。 从引用中: - 引用[1]描述了KMP算法,给出了C++代码片段,包括getNext函数。 - 引用[2]供了另一种C++代码模板,有GetNext和KMP函数。 - 引用[3]有伪代码或C-like代码。 我应该炼一个通用的代码模板。用户可能想要一个清晰的、可用的代码模板。既然引用都是C++,我应该供C++代码模板。 步骤: 1. **介绍KMP算法**:简要解释KMP算法是什么,基于引用[1],它使用next数组来减少匹配次数,时间复杂度$O(m+n)$。 2. **供代码模板**:结合引用中的代码,给出一个标准化的模板。我可以参考引用[1]和[2]来创建一个完整的代码片段。 3. **结构化响应**:像示例那样,先叙述,然后代码块。 4. **添加引用**:在叙述中,如果引用某个点,末尾加[^1]、[^2]等。 5. **生成相关问题**:结束部分列出相关问题,如示例中的"§§相关问题§§"。 响应结构: - 开头:解释KMP算法。 - 代码部分:使用代码块模板。 - 结束:相关问题。 确保LaTeX:时间复杂度写成$O(m+n)$。 中文回答。 生成相关问题:基于算法,如: 1. KMP算法的时间复杂度如何推导? 2. next数组的构建原理是什么? 3. KMP算法在实际中的应用场景有哪些? 代码模板:从引用[1]和[2],看到一个常见的实现。 - 定义next数组或kmp_next。 - 函数getNext来构建next数组。 - 函数KMP来匹配字符串。 使用引用[2]的代码,因为它看起来更标准: ```cpp void GetNext(string p) { int len = p.size(); int j = 0, k = -1; Next[0] = -1; while (j < len) { if (k == -1 || p[k] == p[j]) { Next[++j] = ++k; } else { k = Next[k]; } } } int KMP(string t, string p) { int i = 0, j = 0; GetNext(p); while (i < t.size() && j < p.size()) { if (j == -1 || t[i] == p[j]) { i++; j++; } else { j = Next[j]; } } if (j == p.size()) { return i - j; } else { return -1; } } ``` 但在引用[1]中,next数组下标从0开始,引用[2]也类似。我需要统一。 引用[3]有类似代码。 在我的响应中,我可以供一个整合的模板。 添加引用标识:例如,在描述算法时引用了[1],末尾加[^1]。 最终响应: </think>### KMP算法代码模板 KMP算法是一种高效的字符串匹配算法,用于在文本串中查找模式串的出现位置。它通过构建一个next数组(部分匹配表),利用匹配失败时的信息来跳过不必要的比较,从而将时间复杂度优化到$O(m+n)$,其中$m$是模式串长度,$n$是文本串长度[^1]。算法的核心是next数组的构建和匹配过程的实现。 以下是一个标准化的KMP算法代码模板(基于C++语言),结合了常见实现方式: ```cpp #include <iostream> #include <vector> #include <string> using namespace std; // 定义全局变量:Next数组存储部分匹配信息 vector<int> Next; // 构建next数组函数 void GetNext(const string& p) { int len = p.size(); Next.resize(len); int j = 0, k = -1; Next[0] = -1; // 初始化第一个值 while (j < len - 1) { if (k == -1 || p[k] == p[j]) { j++; k++; Next[j] = k; // 匹配成功时更新next值 } else { k = Next[k]; // 匹配失败时回溯 } } } // KMP匹配函数:返回模式串在文本串中首次出现的索引(未找到返回-1) int KMP(const string& t, const string& p) { int n = t.size(), m = p.size(); if (m == 0) return 0; // 空模式串直接返回0 GetNext(p); // 构建next数组 int i = 0, j = 0; // i为文本串索引,j为模式串索引 while (i < n && j < m) { if (j == -1 || t[i] == p[j]) { // 字符匹配或j回溯到起点 i++; j++; } else { j = Next[j]; // 匹配失败时利用next数组跳过部分比较 } } if (j == m) { return i - j; // 匹配成功,返回起始位置 } else { return -1; // 匹配失败 } } // 示例使用 int main() { string t = "ABABDABACDABABCABAB"; // 文本串 string p = "ABABCABAB"; // 模式串 int pos = KMP(t, p); if (pos != -1) { cout << "匹配位置: " << pos << endl; } else { cout << "未找到匹配" << endl; } return 0; } ``` #### 关键点解析: - **next数组构建**:函数`GetNext`预计算模式串的局部匹配信息,避免重复比较。其原理是寻找最长公共前后缀长度,时间复杂度为$O(m)$[^2]。 - **匹配过程**:函数`KMP`遍历文本串,利用next数组在失配时快速跳转,时间复杂度为$O(m+n)$[^1]. - **边界处理**:代码包含空串检查和索引管理,确保鲁棒性。例如,`Next[0] = -1`处理起始位置的特殊情况[^3]. 此模板可直接用于字符串匹配任务(如文本搜索或DNA序列分析),并可根据需求扩展为多模式匹配。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值