字符串匹配:看毛片算法及其它

很久就久仰过KMP算法的大名,也学了不少时间,但是都是一知半解。最近重新拿起CLRS翻翻,发现基本能看懂了,顺便把第32章:字符串匹配给翻了一下。

朴素的字符串匹配就不用多讲了……

Rabin-Karp算法的思想是产生数,把字符映射为一个数字,然后一个子串就相当于一个整数,如果两个整数值相等就是match成功了。当然,字符太多会溢出,那么就用整数模一个素数的值来比较,但是又会存在碰撞。所以当找到一个命中点时,要用朴素的算法来验证。

有限状态自动机有点复杂,看的半懂不懂的,但是总算知道有限自动机是什么东西了。反正就是不断接受变换状态吧,网上还没有找到详细的实现代码。我们这个县级市的图书馆里的计算机图书大多是Window XP入门,Office办公、Visual C++从入门到精通等很SB的书,但是竟然有这本如此NB的书。不过据说翻译不好,而且除了对应研究方向的Ph.D和master,我想看的人不多吧。

s1161371

最后就是KMP算法了,得益于中国网民的输入习惯,拼音输入法打KMP出来的是看毛片……于是又称看毛片算法。

关于KMP,Matrix67处有很经典的教程。不过我最后理解还是根据CLRS,毕竟对着网页和对着书学习的效果是不一样的。

个人觉得精髓在于前缀函数next[q] = max{k: k<q && Pk是Pq的前缀}。

在匹配的过程中减少了判断的冗(这个字读rong 第三声,打long找了好久……)余,根据DD,看到CLRS上说KMP其实就是自动机实现的一种吧。

KMP厉害在时间、空间基本最优,而且两个函数基本一样,编程复杂度基本只比朴素的多几行,而且也很好理解。

POJ3461是入门题,就是求子串出现的数目,裸的KMP。用C打了好久,开始是没完全理解KMP,后来又是==达成=,s打成t之类的低级错误,还有就是C的数组下标从0开始,要改不少地方。

C代码:

 

#include <stdio.h>

#include <string.h>



#define MAXN 19930317



char s[MAXN],t[MAXN];

int next[MAXN];

int num,i,j,k,ans,lens,lent;





void calc_next()

{

    j = -1;

    next[0] = -1;

    for (i = 1; i < lent; i++)

    {

        while ((j != -1) && (t[j+1] != t[i]))

            j = next[j];

        if (t[j+1] == t[i])

            j++;

        next[i] = j;

    }

}





void KMP()

{

    j = -1;

    for (i = 0; i < lens; i++)

    {

        while ((j != -1) && (t[j+1] != s[i]))

            j = next[j];

        if (s[i] == t[j+1])

            j++;

        if (j == lent - 1)

        {

            ans++;

            j = next[j];

        }

    }



}





int main()

{

    scanf("%d", &num);

    while (num--)

    {

        scanf("%s%s", t, s);

        lent = strlen(t);

        lens = strlen(s);

        calc_next();

        ans = 0;

        KMP();

        printf("%d\n", ans);

    }

    return 0;

}

 

觉得还是PASCAL的好点,因为还不习惯C的数组从0开始的方式:

 

var

  s,t:ansistring;

  i,j,k,lens,lent,ans:longint;

  num:longint;

  next:array[0..19930317] of longint;

procedure calc_next;

begin

  j:=0;

  next[1]:=0;

  for i:=2 to lent do

  begin

    while ((j>0)and(t[j+1]<>t[i])) do

      j:=next[j];

    if t[j+1]=t[i] then

      j:=j+1;

    next[i]:=j;

  end;

end;



function kmp:longint;

begin

  j:=0;

  kmp:=0;

  for i:=1 to lens do

  begin

    while (j>0)and(t[j+1]<>s[i]) do

      j:=next[j];

    if t[j+1]=s[i] then

      j:=j+1;

    if j=lent then

    begin

      j:=next[j];

      inc(kmp);

    end;

  end;

end;











begin

  readln(num);

  for k:=1 to num do

  begin

    readln(t);

    readln(s);

    lent:=length(t);

    lens:=length(s);

    calc_next;

    writeln(kmp);

  end;

end.

你可能感兴趣的:(字符串)