【模板】KMP

KMP算法
贴个链接:http://blog.csdn.net/v_july_v/article/details/7041827
这个博客讲的蛮不错
本人比较懒就不做过多解释了(hhh)
只是重申几个比较核心的思想与概念
1.字符串匹配的加速主要在于在匹配过程中失配的情况下,有效地多往后面跳几个字符,加快匹配速度。
2.KMP中的next数组指的是:到当前位置,前缀串和后缀串的最大重叠长度
3.在失配时,就可以直接把前缀串移到后缀串的位置继续匹配

代码如下

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdio>
using namespace std;
int nxt[1001];
char a[1001000],b[1001];
int main()
{
    scanf("%s%s",a+1,b+1);
    int lena=strlen(a+1);
    int lenb=strlen(b+1);
    int j=0;
    for(int i=2;i<=lenb;i++)//求next[i]
    {
        while(j&&b[j+1]!=b[i]) j=nxt[j];
        j+=(b[j+1]==b[i]);
        nxt[i]=j;
    }
    j=0;
    for(int i=1;i<=lena;i++)//KMP
    {
        while(j&&a[i]!=b[j+1]) j=nxt[j];
        j+=(a[i]==b[j+1]);
        if(j==lenb) printf("%d\n",i-lenb+1);
    }
    for(int i=1;i<=lenb;i++)
    printf("%d ",nxt[i]);
    return 0;
}
<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序列分析),并可根据需求扩展为多模式匹配。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值