kmp算法模板

kmp算法主要是可以高效地在一堆字符串里找到你想要的子串

算法的原理

核心思想:当某个字符匹配失败时,利用之前已经匹配成功的信息,知道部分前缀与后缀是相等的,因此可以利用这些信息跳过一些不必要的比较。

KMP算法中引入了一个关键的数组next,它用于记录模式串中前后字符重复出现的个数,以便在匹配失败时能够知道应该跳过多少字符。next数组的计算基于模式串本身,与主串无关。

比如

有一个主串

ccaaaacdde

和一个子串

acaaaca

加红a的位置是i,c是j+1

此时已经出现不匹配的了但子串匹配并不会从头开始因为此时以j为下标的相等前缀后缀值是1,所以是从下标为1再开始匹配,这就节省了一部分时间

next数组的意思

  1. 核心思想:当某个字符匹配失败时,利用之前已经匹配成功的信息,知道部分前缀与后缀是相等的,因此可以利用这些信息跳过一些不必要的比较。

  2. next数组:KMP算法中引入了一个关键的数组next,它用于记录模式串中前后字符重复出现的个数,以便在匹配失败时能够知道应该跳过多少字符。next数组的计算基于模式串本身,与主串无关。

  3. 下面是kmp算法的例题 洛谷p3375

    题目描述

    给出两个字符串 𝑠1s1​ 和 𝑠2s2​,若 𝑠1s1​ 的区间 [𝑙,𝑟][l,r] 子串与 𝑠2s2​ 完全相同,则称 𝑠2s2​ 在 𝑠1s1​ 中出现了,其出现位置为 𝑙l。
    现在请你求出 𝑠2s2​ 在 𝑠1s1​ 中所有出现的位置。

    定义一个字符串 𝑠s 的 border 为 𝑠s 的一个非 𝑠s 本身的子串 𝑡t,满足 𝑡t 既是 𝑠s 的前缀,又是 𝑠s 的后缀。
    对于 𝑠2s2​,你还需要求出对于其每个前缀 𝑠′s′ 的最长 border 𝑡′t′ 的长度。

    输入格式

    第一行为一个字符串,即为 𝑠1s1​。
    第二行为一个字符串,即为 𝑠2s2​。

    输出格式

    首先输出若干行,每行一个整数,按从小到大的顺序输出 𝑠2s2​ 在 𝑠1s1​ 中出现的位置。
    最后一行输出 ∣𝑠2∣∣s2​∣ 个整数,第 𝑖i 个整数表示 𝑠2s2​ 的长度为 𝑖i 的前缀的最长 border 长度。

    输入输出样例

    输入 #1复制

    ABABABC
    ABA
    

    输出 #1复制

    1
    3
    0 0 1 
  4. 以下是AC代码
    #include<bits/stdc++.h>
    using namespace std;
    const int N = 1e6+10;
    int ne[N];
    char s1[N],s2[N];
    int main(){
    	cin.tie(0);cout.tie(0);
    	cin>>s1+1>>s2+1;//从1开始好处理
    	int x=strlen(s1+1);
    	int y=strlen(s2+1);
        //求next数组
    	for(int i=2,j=0;i<=y;i++){
    		while(j&&s2[i]!=s2[j+1])j=ne[j];//
    		if(s2[i]==s2[j+1])j++;
    		ne[i]=j;
    	}
    	for(int i=1,j=0;i<=x;i++){
    		while(j&&s1[i]!=s2[j+1])j=ne[j];
    		if(s1[i]==s2[j+1])j++;
    		if(j==y){
    			cout<<i-y+1<<endl;
    			j=ne[j];
    		}
    	}
    	for(int i=1;i<=y;i++){
    		cout<<ne[i]<<' ';
    	}
    	return 0;
    }

  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值