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

很久就久仰过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.

posted on 2011-07-06 15:09  oa414  阅读(1650)  评论(0编辑  收藏  举报

导航