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]就好了!,可能不會動,但是就附上圖片吧!
這裏寫圖片描述
那麼這麼預處理呢?
就是這個函數:

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.這是因爲這個圖!
這裏寫圖片描述
所以是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玄學問題,暫等更新……

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章