KMP算法

前言

kmp算法又称模式匹配算法,能够在线性时间内判定字符串A[1-N]是否是字符串B[1-M]的子串。(<=N<M<=1E6)

bf算法像不像你那个不会kmp的女友,她完全不会考虑子串与主串已匹配区间,她只会想着下一个,在从头慢慢匹配,他不会记得你们二个已经匹配成功了k个相同的字符。

一、问题导出

① 字符串匹配例题

在这里插入图片描述

② BF解决方案

给定主串数组A[1-M],子串数组P[1-N],分别以i,j为其字符串比较过程中的当前下标。(1<=i<=M,1<=j<=N)
令i起始比较位置为,T。
每次比较A[i]是否等于p[j],等于则i++,j++直至j==n输出位置下标i-j(这里数组都从1开始)。
否则i回退到T+1,j回退到1。

③ 代码实现

时间复杂度O(n*m),空间复杂度O(1)

#include <iostream>
#include <string.h>
#include <algorithm>
using namespace std;
const int N=1e6+10;
int ne[N];
char a[N],p[N];
int n,m;
int main()
{
    cin>>n>>p+1>>m>>a+1;
    for(int i=1,j=1;i<=m;i++)
    {
        int k=i;
        while(a[k]==p[j]) 
        {
            k++;
            j++;
            if(j==n) cout<<(k-j)<<" ";
        }
        
        
        
        j=1;
    }
    return 0;
}

二、引入KMP算法思想

① kmp算法提高效率解释

kmp算法本质上是在BF算法的基础上减少回退次数,达到优化效果。

② kmp算法详解

假设子串与主串前【1-j】都匹配(1<=j<m),但a[i+1]!=p[j+1]。(数组下标都从1开始)
如图:
ababcababdababd
对此肯定要移动子串,继续与主串进行匹配。
对于BF算法中,遇此情况是,回退到,T+1,j=1;
在此我们对已匹配区间【1-j】性质进行分析,考虑移动多少位。
注:这里说的移动几位,移动后应满足,移动后的区间依然为子串与主串匹配区间,即匹配空间范围是0<=k<=j-1(这里的移位是过滤掉原匹配子串空间移动后成子串不匹配空间,而变成移动后又变成子串匹配空间,但子串匹配空间变小了,由此继续比较a[i+1]是否等于p[j+1]);
假设可以移动一位,就可以满足区间【1-j-1】又是一个子串与主串的匹配区间,
即:
在这里插入图片描述
为此,对于能移动k位,即原子串与主串匹配长度区间的字符串要满足前缀与后缀相等,且相等的长度为【j-k】(j为匹配长度,k为移动位数)。

③ 代码实现

#include <iostream>
#include <algorithm>
#include <string.h>
using namespace std;

#define _for(i,j,a,b) for( int i=(a),j=0;i<=(b); ++i)
#define _fo(i,a,b) for( int i=(a);i<=(b); ++i)
#define _scan(a,b) scanf("%d%d",&a,&b)
const int N=1e6+10;
int ne[N];
char p[N],a[N];
int n,m;
int main(void)
{
   
   cin>>n>>(p+1)>>m>>(a+1);
   _for(i,j,2,n)
   {
       while(j&&p[i]!=p[j+1]) j=ne[j];
       if(p[i]==p[j+1]) j++;
       ne[i]=j;
   }
   //_fo(i,1,n) cout<<ne[i]<< " ";
   //cout<<endl;
   _for(i,j,1,m)
   {
       while(j&&a[i]!=p[j+1]) j=ne[j];
       if(a[i]==p[j+1]) j++;
       if(j==n)
       {
           cout<<i-j<<" ";
           j=ne[j];
       }
   }
  
    return 0;
}
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数论只会a mod b

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值