首页 > 其他分享 >KMP

KMP

时间:2024-06-08 23:54:42浏览次数:16  
标签:++ 复杂度 int KMP 长度 pi

前缀函数

给定一个长度为 \(n\) 的字符串 \(s\)(设下标从 \(1\) 开始),其 前缀函数 定义为一个长度为 \(n\) 的整数数组 \(\pi\),其中 \(\pi_i\) 满足:

  • \(s[1,\pi_i]=s[n-\pi_i+1,n]\) 且 \(\pi_i \ne n\)。
  • 如果没有为 \(0\)。

最朴素的方法求 \(\pi\) 时间复杂度为 \(O(n^3)\)。

优化 1

结论:\(\pi_{i+1} \le \pi_{i}+1\)。

每次当前字符串扩大一位,如果 \(s'[\pi_i+1]=s'[i+1]\),那么 \(\pi_{i+1}=\pi_{i}+1\),反之,\(\pi_{i+1} \le \pi_{i}\)。

这样时间复杂度降至 \(O(n^2)\)。

优化 2

当 \(s'[\pi_i+1]=s'[i+1]\) 时 \(\pi_{i+1}=\pi_{i}+1\),那么当 \(s'[\pi_i+1] \ne s'[i+1]\) 时,我们需要找到一个长度 \(j\) 使得 \(s'[1,j]=s'[i-j+2,i+1]\)。可以发现:

\[s[1,j]=s[i-j+2,i+1]=s[\pi_{i}-j+1,\pi_{i}] \]

此时 \(j=\pi_{\pi_{i-1}}\),因此我们得到 \(j_{n}=\pi_{j_{n-1}-1}\)。

时间复杂度降至 \(O(n)\)。

// 此处 s 的下标从 1 开始
for (int i = 1; i < n; i++) {
  int j = pi[i - 1];
  while (j > 0 && s[i] != s[j]) {
    j = pi[j - 1];
  }
  if (s[i] == s[j]) {
    j++;
  }
  pi[i] = j;
}

查找子串(KMP 算法)

给定字符串 \(s,t\),长度分别为 \(n,m\),求 \(t\) 在 \(s\) 中出现的下标。

设字符串 \(M=t+\#+s\),其中 \(\#\) 替换为 \(s,t\) 中不存在的字符。这样 \(\pi_{1 \sim m}\) 均 \(<m\),\(\#\) 所在位置一定为 \(0\),此后当 \(\pi_i=m\) 时说明 \(s\) 中出现 \(t\),下标为 \(i-2m\)。

由于长度永远不会超过 \(m\),因为中间的 \(\#\),所以只需求出 \(t\) 的前缀数组即可,对 \(s\) 维护变量 \(j\)。

for (int i = 0, j = 0; i < n; i++) {
  while (j > 0 && b[j] != a[i]) {
    j = pi[j - 1];
  }
  if (b[j] == a[i]) {
    j++;
  }
  if (j == m) {
    cout << i - m + 2 << "\n";
  }
}

标签:++,复杂度,int,KMP,长度,pi
From: https://www.cnblogs.com/unino/p/18239121

相关文章

  • 模式匹配---kmp算法
    模式匹配--Kmp算法暴力匹配暴力匹配,既普通模式匹配,主串一个一个地与子串进行比对,一旦匹配失败就跳回主串原指针的下一个重新回溯,子串跳回第一个,重新开始匹配。主串BABCBFDAB下标012345678子串BCB主串原指针指向下标为......
  • KMP算法
    KMP算法KMP算法是一个解决模式串在文本串是否出现过,如果出现过,最早出现的位置的经典算法。重点是找到字符串的最长公共前后缀。用最长公共前后缀在匹配的同时,实现快速跳转。#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintINF=0x3f3f3f3f;......
  • 算法课程笔记——KMP&字符串哈希
    算法课程笔记——KMP&字符串哈希就是模板题aba是前后缀,真前后缀就只有a/b /a避免出现不同字符有相同的值相当于进制如果你能熟练掌握正则表达式,用库还能更快......
  • 数据结构中的算法-KMP算法
    一、KMP算法串的模式匹配操作是指在当前串(主串)中寻找子串(模式串)的过程。当在主串中找到了和模式串相同的子串时,模式匹配成功;否则,模式匹配失败。当模式匹配成功时,返回模式串的首字符在主串中的位置;否则,返回-1。1.1暴力模式匹配算法(Brute-Force)假设有主串S和模式串T,T的长度为......
  • kmp的神奇之处
    $kmp$想必大家都不陌生,这里先贴个模板hh从0开始:for(inti=1,j=0;i<s2.length();i++){while(j&&s2[i]!=s2[j])j=ne[j-1];if(s2[i]==s2[j])j++;ne[i]=j;}for(inti=0,j=0;i<s1.l......
  • 【字符串常用算法】——KMP算法(你别闲烦 超详细,给你解释明白)
    1、字符串匹配——KMP算法    当我们想要想要在一个字符串中找到一个子串,如在字符串"aaabaaacaaad"中查找是否存在模式串"aaad"。首先常规的算法如下:1、先比较字符串与模式串 第一个是否相等,相等则匹配下一个2、比较第二个字符是否相等,相等则匹配下一个3、比......
  • 第二题-塔子哥的编译原理实验【KMP】
    本题的模式串可以展开,使用栈来模拟即可,每次一个(放入栈中对应的位置以及前面的数量,每次)弹出栈顶元素,然后将栈顶元素的数量乘以当前的字符串加上栈顶元素的前面的字符串加入到模式串中即可。需要注意有可能模式串非常长,所以中间需要判断是否已经超过了匹配串的长度,超过则直接返......
  • kmp算法java
    KMP是三位大牛:D.E.Knuth、J.H.Morris和V.R.Pratt同时发现的。其中第一位就是《计算机程序设计艺术》的作者!!KMP算法要解决的问题就是在字符串(也叫主串)中的模式(pattern)定位问题。说简单点就是我们平时常说的关键字搜索。模式串就是关键字(接下来称它为P),如果它在一个主串(接下来......
  • JAVA KMP 纯模板
    纯模板记忆使用~classMain{staticchar[]s1;staticchar[]s2;staticint[]next;publicstaticvoidmain(String[]args){Scannerin=newScanner(System.in);s1=in.nextLine().toCharArray();s2=in.nextLine().to......
  • 记字符串匹配KMP算法
    字符串匹配是一类经典的问题,在字符串s中找出模式串t第一个元素的下标,如果没有匹配到,则返回-1。此问题在leetcode中甚至归类为简单。解决此问题最直接的思路是使用暴力解法,从第0个元素开始逐个比较元素,当字符不匹配时,s的指针向前移动一位,不断重复。这种思路最简单且直接,但是无法通......