KMP 与字典树

KMP 算法概述KMP 算法全称是 Knuth-Morris-Pratt 字符串查找算法,是用于在一个字符串(匹配串)中查找另一个字符串(模式串)的快速算法KMP算法会在匹配前预处理模式串 PPP 得到 fail 数组, 借助 fail 数组,可以在匹配过程中减少很多冗余的操作,时间复杂度 : O(n+m)\mathcal{O}(n + m)O(n+m), 其中, nnn 和 mmm 是两个串的长度算法流程fail 数组的预处理KMP 算法的核心是 fail 数组,对于字符串 s=s0,s1,s
摘要由CSDN通过智能技术生成

KMP 算法

概述

KMP 算法全称是 Knuth-Morris-Pratt 字符串查找算法,是用于在一个字符串(匹配串)中查找另一个字符串(模式串)的快速算法

KMP算法会在匹配前预处理模式串 P P P 得到 fail 数组, 借助 fail 数组,可以在匹配过程中减少很多冗余的操作,时间复杂度 : O ( n + m ) \mathcal{O}(n + m) O(n+m), 其中, n n n m m m 是两个串的长度

算法流程

fail 数组的预处理

KMP 算法的核心是 fail 数组,对于字符串 s = s 0 , s 1 , s 2 , … , s n − 1 s = s_{0},s_{1},s_{2},\dots,s_{n - 1} s=s0,s1,s2,,sn1 ,如果 j j j 满足 s 0 … i = s i − j … i s_{0 \dots i} = s_{i - j \dots i} s0i=siji 的最大值,则 f a i l [ i ] = j fail[i] = j fail[i]=j 注意: j ≤ i j \le i ji 其中, s a … b s_{a \dots b} sab 表示字符串 s s s a a a 号位到 b b b 号位的子串

对于不存在 s 0 … i = s i − j … i s_{0 \dots i} = s_{i - j \dots i} s0i=siji 的最大值,fail[i] = -1

img

对于字符串 “aababaab” 则 fail 值如下:

img

匹配过程

img

对于上面的过程,当 a? 比较时失败了,那么我们要把母串的起始位置移动到下一个位置,对于 2 2 2 指向的匹配,这时候我们没必要从头开始比较,因为我们知道 fail[i] = 1 如果红色块可以完美匹配,那么应该等于 4 4 4 , 第 3 3 3, 4 4 4 次也是同理,所以直接跳到匹配 %5%

这就是 KMP 的本质:利用已经计算过了的信息加速匹配过程

代码

#include <iostream>
#include <cstring>
using namespace std;
const int maxn = 100;
int fail[maxn];
void getFail(char *P) {
   
    int m = strlen(P);
    fail[0] = -1;
	for (int i = 1; i < m; ++i) {
   
    	int j = fail[i - 1];
        while (j >= 0 && P[j + 1] != P[i]) {
   
            j = fail[j];
        }
        if (P[j + 1] == P[i]) {
   
            j++;
        }
        fail[i] = j;
    }
}
int KMP(char *T, char *P) {
   
    int n = strlen(T), m = strlen(P);
    int j = -1;
    for (int i = 0; i < n; 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值