KMP算法及POJ上相关的题目

来源:互联网 发布:mac重装系统全盘格式化 编辑:程序博客网 时间:2024/06/05 11:37

KMP算法的介绍与POJ上一些相关的题目

一 :KMP算法的介绍

KMP算法的核心是构造next[]数组。先搞清楚next数组的含义。例如:next[j] = k;这样的一个式子表示的含义是:当主串中第i个元素与模式串中的第j个元素匹配失败时,应该保持i指针不动,而将模式串中的j指针移动到k这个位置。然后将主串中第i个元素与模式串中的第j个元素匹配。若匹配的话就同时移动i和j指针。不匹配的话,再次计算next[k] = ?.....依次进行。

所以KMP算法的本质就是主串中i指针不回溯。

      下面来一步步的证明next[]数组的构造过程。

第一步:

      设主串S = “s1s2…sn”,   T= “t1t2…tm”.

若满足:

(1) “si-j+1…si-1” = “t1..tj-1”;

(2)  “t1t2…tk-1”= “tj-k+1tj-k+1…tj-1”;(1<k<j)

在同时满足(1),(2)的条件下,可以直接比较si 和 tk

若对于任意的1<k<j,条件(2)都不满足,则直接比较si和t1

第二步:

模式串t的next函数:

当si 和tj  匹配失败时,si与tnext(j) 匹配。

第三步:

求 next()函数的算法:因为已知next(0) = -1,只要找出next(j+1)与next(j)之间的关系,就可以求出所有的next(j).

初始算法:

(1)  初值next(0) = -1;

(2)  设next(j) = k, 说明“t1t2…tk-1”= “tj-k+1tj-k+1…tj-1”;(1<k<j)

     (2-1) 若tj = tk, 则有“t1t2…tk-1tk” = “tj-k+1tj-k+1…tj-1tj”; (1<k<j)

           所以next(j+1) = next(j) + 1 = k + 1;

      (2-2)若tj  tk,因为有next(k) = k,

则必然有:“t1t2…tk’-1”= “tj-k’+1…tj-1”;

(2-2-1) 若tj = tk’,则next(j+1) =next(next(j)) + 1 = k+ 1;

(2-2-2)若tj  tk’ ,则重复(2-2).直到不存在K(n),则next(j+1)=0;

第四步:

next函数算法:

void get_next(sstring T, int &next[])

{

  //求模式串Tnext函数值并存入数组next

  j=1; k=next[j]=0;

  while (j<T[0])    //计算next(j)next(2)next(T[0])T[0]T的长度

//但并不意味着只循环m-1次,因为在循环体中j的值可能不发生变化

    if (k==0||T[j]==T[k])// 没有重叠真子串和(有重叠真子串但T[j]==T[k])时

                     //都应该得出next(j+1)的值

      next[++j]=++k;//书上:{++j ; ++k;next[j]=k;}

    else k=next(k);//否则,得不出next(j+1)的值,所以j不变,k退回到next(k),重复匹配。

}//end ofget_next

二:POJ上一些相关的题目

由于初学KMP,所以做的都是一些比较简单的题目。

(参考博客:http://blog.csdn.net/lalor/article/details/7358956)

 

1.   POJ 3461 http://poj.org/problem?id=3461

题意:求模式串在主串中出现的次数。当匹配一次成功的时候,假设最后一个字符没有匹配成功,则j=next[j];所以只需把匹配的过程稍微改变一下即可。

 

2: POJ 2752 http://poj.org/problem?id=2752

题意:求给定串中所有前缀和后缀相等的情况。


假设当前j指针指向最后一个字符,next(j)= j,所以3-1区间与4-5区间相同。

接着next(j) = j’’,所以①与②区间相同。假设存在一个点,把4-5区间分成了③,④。因为①+②与③+④相同,所以③与④相同,所以①与④相同。

3.POJ 2406 http://poj.org/problem?id=2406

题意:求给定串中重复串的个数。

用到了:if(len %(len – next[len])== 0) ans = len / (len – next[len]);

不会证明。

4.POJ 1961 http://poj.org/problem?id=1961

题意:求给定串中所有前缀的重复串的个数。

与上一题一样的思路。

原创粉丝点击