首页 > 其他分享 >KMP

KMP

时间:2024-02-08 20:13:21浏览次数:24  
标签:dots 匹配 leftarrow s2 KMP fail 个字符

KMP 主要用于求解以下问题:

求字符串 \(t\) 在字符串 \(s\) 中出现的所有位置。

如果存在 \(s[i \dots j]\) 与 \(t\) 完全相同,则称 \(t\) 在位置 \(i\) 出现了。

用 \(s[l \dots r]\) 表示字符串 \(s\) 的第 \(l\) 个字符到第 \(r-1\) 个字符所组成的字符串,下标从 \(1\) 开始。用 \(\operatorname{len}(s)\) 表示字符串 \(s\) 的长度。

设 \(fail_i\) 表示 \(s2[1 \dots i+1]\) 的前 \(fail_i\) 个字符与 \(s2[1 \dots i+1]\) 的后 \(fail_i\) 个字符完全相同。特别的,\(fail_1=0\)。如 \(s2=\)1234123,那么 \(fail=\{0,0,0,0,1,2,3\}\)。这样在匹配到 \(s2\) 串的第 \(i\) 位的时候,如果匹配失败,就继续用 \(s2\) 的第 \(fail_{i-1}\) 位匹配。时间复杂度接近 \(\mathcal{O}(N+M)\)。

那么如何计算 \(fail\) 数组呢?

如果已经处理到第 \(i\) 位,先让 \(j=fail_{i-1}\),表示 \(s2[1 \dots j+1]=s2[i-j+1 \dots i-1]\)。

如果 \(s2_i \ne s2_{j+1}\),就让 \(j=fail_j\),因为这个子串的前 \(fail_j\) 个字符和后 \(fail_j\) 个字符完全相同。然后一直这样判断。直到 \(s2_i=s2_{j+1}\) 或 \(j=0\) 就结束。接下来判断现在这一位是否匹配,也就是判断 \(fail_i=fail_{j+1}\)。如果是,就让 \(j\) 加一。

让 \(fail_i=j\),这一位就计算完了。

如字符串 abacabacd。初始时 \(j=0\)。步骤如下。

  • \(i=2\)

\(s_i \ne s_{j+1}\),所以 \(fail_2 \leftarrow j=0\)。

  • \(i=3\)

\(s_i=s_{j+1}\),所以 \(j \leftarrow j+1=1,fail_3 \leftarrow j=1\)。

  • \(i=4\)

\(j \leftarrow fail_j=0\)。

\(s_i \ne s_{j+1}\),所以 \(fail_4 \leftarrow j=0\)。

  • \(i=5\)

\(s_i=s_{j+1}\),所以 \(j \leftarrow j+1=1,fail_5 \leftarrow j=1\)。

  • \(i=6\)

\(s_i=s_{j+1}\),所以 \(j \leftarrow j+1=2,fail_6 \leftarrow j=2\)。

  • \(i=7\)

\(s_i=s_{j+1}\),所以 \(j \leftarrow j+1=3,fail_7 \leftarrow j=3\)。

  • \(i=8\)

\(j \leftarrow fail_j=1\)

\(j \leftarrow fail_j=0\)

\(s_i \ne s_{j+1}\),所以 \(fail_8 \leftarrow j=0\)。

此时 \(fail\) 数组就计算出来了。

接着要进行匹配。匹配和处理的代码很像,如果第 \(i\) 位匹配失败了,就继续用第 \(fail_i\) 位进行匹配。如果 \(j=\operatorname{len}(s2)\),就说明 \(s2\) 在 \(s1\) 的第 \(i-j+1\) 位出现了。

这就是 KMP 算法。时间复杂度约为 \(\mathcal{O}(N+M)\)。

例1 洛谷-P3375

本题为模板题。

代码

标签:dots,匹配,leftarrow,s2,KMP,fail,个字符
From: https://www.cnblogs.com/lrxmg139/p/18012094

相关文章

  • KMP算法
    目录感悟kmp已经整了很多次了,从一开始的不懂到之前一次的似懂非懂,这次再刷字符串算法,一定搞懂寄,又有点糊里糊涂的感悟有点晕,next数组和整体的顺序上已经理解了存在的问题用next数组查找的时候要用while循环去查找,因为如果用if来查找,匹配到本次不一样,回退后仍然可能不一样......
  • KMP 学习笔记
    前言——\(char\)与\(string\)有的时候\(char\)数组确实比\(string\)好用,且字符串长度很大时\(string\)会被卡掉,所以不要犯懒,老实用\(char\),\(string\)可以用但是慎用。同时很多情况下为了方便和减少出错,我们会想办法把字符串的坐标从\(0\simlen-1\)变成\(1......
  • DFA , KMP 和 AC自动机
    一些废话更更更好的观感:3ZincBlog。由于Github没法被百度爬到,所以决定Cnblogs和3ZincBlog同时更新。希望您支持!DFA:确定有限状态自动机确定有限状态自动机(DFA,DeterministicFiniteAutomation),能够按顺序接受一个信号序列并判断其是否符合DFA所要判断的条件。放在OI......
  • 【板子】KMP
    //lgp3375//Copyrightyeyou26#include<bits/stdc++.h>usingnamespacestd;charp[1000005],s[1000005];intlenp,lens;intlst[1000005];voidinit();voidpre_work();voidkmp();voidout_put();intmain(){freopen("working.in",&qu......
  • 「笔记」Z 函数(扩展 KMP)
    目录写在前面简介算法流程代码复杂度证明求串\(t\)所有后缀与串\(s\)的最长公共前缀。下位替代与KMP的关系例题匹配子串求字符串周期P5410【模板】扩展KMP/exKMP(Z函数)P7114[NOIP2020]字符串匹配P9576「TAOI-2」Ciallo~(∠・ω<)⌒★写在最后写在前面这b东西感觉和......
  • 学习笔记——KMP模式匹配
    KMP模式匹配KMP算法能够在线性时间内判定字符串\(A\left[1\simN\right]\)是否是字符串\(B\left[1\simM\right]\)的字串,并求出字符串\(A\)在字符串\(B\)中各次出现的位置。详细来讲,KMP算法分为两步。对字符串\(A\)进行自我匹配求出一个数组\(next\),\(next\lef......
  • KMP
    KMPvoidgetnext(char*p){intlenp=strlen(p);nextt[0]=-1;intk=-1;intj=0;while(j<lenp-1){//p[k]表示前缀,p[j]表示后缀(并没有“真”!)if(k==-1||p[j]==p[k])//j在这{j++;//j+1在这k++;//k=k+1//---->若......
  • kmp算法的理解与记忆
    首先有两步,1求next数组,2进行比对。我这种是数组后移的方法,即第一个数是-1。步骤就是如果前后缀不相等,j就要后撤,要后撤因此要有范围。j>=0;如果相等就j++;每一次循环求出对应的next[i]。要注意的点是因为我这是数组后移的方法,因此比较用next[j+1]比较。2比对跟求next差不多......
  • 【学习笔记】KMP 相关算法
    KMP单模式串匹配,比较平凡所以不说了,比较有借鉴意义的每次拓展一位和\(nxt\)数组能极大减少不合法的匹配,时间复杂度\(O(|s|+|t|)\)。引出一个定义,记满足\(s[1,i]=s[|s|-i+1,|s|]\)的前缀为字符串\(s\)的\(\mathrm{border}\),所有的\(\mathrm{border}\)构成\(\mathrm{Bo......
  • 【CF30E】Tricky and Clever Password 题解(manacher + exKMP)
    manacher+exKMP+二分。感觉是最粗暴的方法,想出来之后自己硬莽了4k,荣获题解区最长。Solution约定:下文所提及到的所有的回文串,均指奇长度回文串。显然把题目拆成两个部分,中间的回文串,以及两边相同的连续子串。考虑一下从哪个入手比较好。忘记是咋想的了,易得从两边相同......