【KMP字符串匹配算法】自留用學習

這個算法經常忘記,今天看了記錄一下心得,自留用。

講得比較好的:
字符串匹配算法KMP詳細解釋——深入理解
講的比較詳細的:
字符串匹配KMP算法的理解(詳細)
簡潔易懂版本:
轉載一篇單字符串匹配KMP算法最好理解的文章

思路:

一般都先講暴力匹配,這種情況下,每次都從字符串開頭開始匹配,當子串長M,父串長N,複雜度是O(M*N)

匹配串的時候,例如:ABCDABD,每次都從頭開始匹配,每次都要回溯子串到最初,這樣沒有利用已經匹配上的信息,例如:匹配到第二個B時失配,我們知道父串前面有ABCDA,所以如果從頭開始匹配,可以直接從B開始匹配,因爲知道前面已經有一個A了。 這樣就利用了已知信息。
爲了得到這樣的信息,需要生成下面的next表。
在這裏插入圖片描述
A從子串首字符開始匹配,B從第二個字符開始匹配,其他的由於沒有重複的結構,只能從頭暴力匹配了。

如何生成next表:

從上面的描述我們知道,next表生成只與子串相關,與父串沒關係。
在這裏插入圖片描述

如何使用next表:

用i,j標識父串和子串目前匹配到的位置,
現在每次需要回溯的距離=目前子串匹配到位置-next[i]

例如:BBC  ABCDAB  ABCD  
          ABCDABD

此時匹配到D,不匹配了,則 i=i+4 且 j=2。

例如:BBC  ABCDAB  ABCD  
              ABCDABD

子串和父串的匹配進度都前進了一大截,節省了(2*子串長+2)次匹配。

代碼:

(c代碼是別人擼的,我就照着寫了下思考了一下,下面的python是我寫的)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define N 100
void print(int a[],int len)
{
    int i=0;
    while(i<len)
    {
        printf("%d ",a[i]);
        i++;
    }
    printf("\n");
}

void prints(char a[],int s,int e)
{
    int i=s;
    while(i<e)
    {
        printf("%c",a[i]);
        i++;
    }
    printf("\n");
}
void cal_next(char * str,int * next,int len)
{
    int i,j;
    next[0]=-1;
    for(i=1; i<len; i++)
    {
        j=next[i-1];
        while(str[j+1]!=str[i]&&(j>=0))
        {
            j=next[j];
        }
        if(str[i] == str[j+1])
        {
            next[i]=j+1;
        }
        else
        {
            next[i]=-1;
        }
    }
    print(next,len);
}

int KMP(char * str,int slen,char* ptr,int plen,int *next)
{
    int s_i=0,p_i=0;
    while(s_i<slen &&p_i<plen)
    {
        if(str[s_i]==ptr[p_i])
        {
            s_i++;
            p_i++;
        }
        else
        {
            if(p_i==0)
                s_i++;
            else
                p_i=next[p_i-1]+1;
        }
    }
    return (p_i==plen)?(s_i-plen):-1;


}

int main()
{
    char str[N]= {0};
    char ptr[N]= {0};
    int slen,plen;
    int next[N];

    while(scanf("%s%s",str,ptr))
    {
        slen=strlen(str);
        plen=strlen(ptr);
        cal_next(ptr,next,plen); //計算next數組
        printf("%d\n",KMP(str,slen,ptr,plen,next));

    }
    return 0;
}

python:

# KMP算法
string,strp=input().split(",")
next=[0 for n in range(0,len(strp))] 
for i in range(0,len(strp)):
    if i==0:
        next[0]=-1
        continue
    j=next[i-1]
    while(strp[j+1]!=strp[i] and (j>=0)):
        j=next[j]
    if(strp[i]==strp[j+1]):
        next[i]=j+1
    else:
        next[i]=-1
print(next)
s_i=0
p_i=0
while(s_i<len(string) and p_i<len(strp)):
    if(string[s_i]==strp[p_i]):
        s_i+=1
        p_i+=1
    else:
        if(p_i==0):
            s_i+=1
        else:
            p_i=next[p_i-1]+1

if i==len(strp):
    print(i)
else:
    print(-1)

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