KMP---字符串匹配

KMP—字符串匹配

介绍:

如果有一个题目,说明的是在一个母串之中找到一个字符串s出现了几次的时候,问你输出次数?

1.暴力,枚举每个位置  时间复杂度 O(N*M)
2.使用KMP  时间复杂度 O(M+N)

1.暴力的算法

无需介绍吧!
直接上算法!

#include <bits/stdc++.h>
using namespace std;
int main()
{
    string mother,s;
    int ans=0;
    cin>>mother>>s;

    int len=s.length();
    int l=mother.length();

    for(int i=0; i<l-len+1; i++)
    {
        string t;
        t=mother.substr(i,len);
        if(t==s)
            ans++;
    }
    printf("%d\n",ans);
    return 0;
}

2.KMP算法

先上算法,之后再来讲解,呵呵!

#include <iostream>
#include <stdio.h>
#include <map>
#include <cstring>
using namespace std;
const int N=100005;
int p[N];
char s[N],t[N*10];
void getp(int n)
{
    p[0]=-1;
    for(int i=1,j=-1; i<=n; i++)
    {
        while(j>=0&&s[j+1]!=s[i])
        {
            j=p[j];
        }
        p[i]=++j;
    }
}

int KMP(int n,int m)
{
    int ret=0;
    for(int i=1,j=0; i<=m; i++)
    {
        while(j>=0&&s[j+1]!=t[i])
        {
            j=p[j];
        }
        j++;//ºóɨһλ!! 
        if(j==n)
        {
            ret++;
            j=p[j];
        }
    }
    return ret;
}
int main()
{
    int n;
    scanf("%d",&n);
    while(n--)
    {
        scanf("%s",s+1);
        int n=strlen(s+1);
        getp(n);
        scanf("%s",t+1);
        int m=strlen(t+1);

        printf("%d\n",KMP(n,m));
    }
}

分析

对于一个字符串的匹配,如果找的了NO.i的位置无法匹配,我们通常会开始继续匹配,但是比如abababa,后来又来了ababca,很明显,在s的char c位置出现了不够匹配,但是,如果是暴力的话就是之后继续判断,但是可以相处一个使得最大的前缀和等于后缀和的是将,储存在花掉匹配的i点记为p[i]就好了!,可能不会动,但是就附上图片吧!
《KMP---字符串匹配》
那么这么预处理呢?
就是这个函数:

void getp(int n)
{
    p[0]=-1;
    for(int i=1,j=-1; i<=n; i++)
    {
        while(j>=0&&s[j+1]!=s[i])
        {
            j=p[j];
        }
        p[i]=++j;
    }
}

p[0]此时的作用只是为了辅助p[1~len]的促成罢了,但是j=-1的初始化真的要好好的去理解啊!while循环的跳出条件就是

while(j>=0&&s[j+1]!=s[i])

那么为什么是这两个数据呢
1.j>=0,就是说万一根本没有最长前缀的事情,所以就跳出来,恰是-1,然后j++,就片尾了0,再赋值,之后就会使得i+1的位置是带着p[i]=0,的情况下去去搜索,去预处理,是不是很妙?
2.这是因为这个图!
《KMP---字符串匹配》
所以是while (s[i]!=s[j+1])

十分好玩!比较的函数KMP!

代码:

int KMP(int n,int m)
{
    int ret=0;
    for(int i=1,j=0; i<=m; i++)
    {
        while(j>=0&&s[j+1]!=t[i])
        {
            j=p[j];
        }
        j++;
        if(j==n)
        {
            ret++;
            j=p[j]; //*********
        }
    }
    return ret;
}

只要还是注释带”*”号的地方,就是将来说如果匹配成功的话就继续匹配,在p[j]的位置上下去就好了!,但是有一些题目j=0,为什么?比如
剪花布条
因为这个题目是减下来的,也就是说剪掉就没了!

注释:

注:
之后还有更多好玩的KMP玄学问题,暂等更新……

    原文作者:KMP算法
    原文地址: https://blog.csdn.net/qq_39809664/article/details/78001552
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞