pku 2406 kmp 解题报告

一、 题目: Power Strings

二、 题意: http://acm.pku.edu.cn/JudgeOnline/problem?id=2406

三、 解决办法:kmp

        首先要理解kmp的基本原理!对于kmp算法,由于我的数据结构的老师没有讲述到,就只好我自己去看书了,然而我本人智商有限,看这哪几页,也看不懂到底再说什么。简简单单的几行代码却让人想得头都晕!终于看到网上有关kmp算法相解决,再结合数据结构的介绍,才勉强明白了!那么,解这道题就简单的多了!

        这里我就自己讲讲kmp算法,看看自己是否真正对kmp算法弄明白!

        Kmp算法是模式匹配的一种改进算法!

        如果按照传统的算法:

//参考《数据结构》中的程序

int Index(String S,String T,int pos)

{
   i = pos; j = 1;                  //
这里的串的第1个元素下标是1
   while (i <= S.Length && j <= T.Length)
   {
        if (S[i] == T[j]) {++i; ++j;}
        else     {i = i – j + 2; j = 1;}
   }
   if (j > T.Length)    return I - T.Length;//
匹配成功
   else return 0;
}

仍然用《数据结构》所讲述的例子分析:A=ababcabcacbabB=abcac

在第一趟匹配:i = 3; j = 3;

在第二趟匹配:i= 2; j = 2;

我仅仅说到这里,i其实在反复回溯,又j也在回溯,这样的话,时间复杂度就大很多了!

kmp算法的改进就在于:每当一趟匹配过程中出现字符不相等的情况下,不需要回溯指针i。从而将时间复杂度大大降低!

//参考《数据结构》中的程序

int Index_KMP(SString S, SString T, int pos)

{

//利用模式串Tnext函数求T在主串S中第pos个字符之后的位置

//kmp算法。其中,T非空,1<=pos<=StrLength(S)

   i = pos;    j = 1;

   while (i <= S[0] && j <= T[0])

   { 

       //继续比较后续字符

       if (j == 0 || S[i] == T[j])

       {

           ++i;

           ++j;

       }

       //模式串向右移动

       else

       {

           j = next[j];

       }

    }

    if (j > T[0])

{

  return i – T[0];

}

else

{

  return 0;

}

}//

下面还是以教材中的例子进行说明:

期中需要说明的是:我们预处理出这样一个数组next[j],表示当匹配到T数组的第j个字母而第j+1个字母不能匹配了时,新的j最大是多少。next[j]应该是所有满足T[1..next[j]]=S[j-next[j]+1..j]的最大值。

S=acaaabaabcacaabc

T=abcac

刚开始:  i = 1;    j = 1;

执行:if (j == 0 || S[i] == T[j])

       {

           ++i;

           ++j;

       }

则凡是主串与模式串可以匹配的话,均++i,++j;但遇到S[i] != T[j],模式串向右移动, j = next[j];则不必要考虑指针i的问题啦!节省了时间!但现在问题是:next[j]如何计算出来?

next[j]的定义可知,j的值与S无关!而当遇到主串与模式串不能匹配的时候,就必须考虑到j的值应为多少,即在之前匹配成功多少个?所以我们可以在匹配成功的情况下同时记录next[i]=j,一旦遇到匹配不成功时,则将j=next[j],这样就如课本所说,做到滑过去第i个匹配的字符!实质就是模式串的自我匹配!

程序:

i = 1;j = 0;next[0] = -1;

while (i < T[0])

{

if (j == 0 || T[i] == T[j])

 {

    if (T[i] != T[j])

         {

++i; ++j;next[i] = j;                          

    }

else

{

         j = next[j];

         }

 }

}

再一次改进:

i = 1;j = 0;next[0] = -1;

while (i < T[0])

{

if (j == 0 || T[i] == T[j])

 {

++i; ++j;

    if (T[i] != T[j])

         {

next[i] = j;                       

}

else

{

   next[i] = next[j];

}

else

{

         j = next[j];

}

}//

 

 

现在回到题目:Power Strings。由题意可知就是模式串的自我匹配!问题就变得简单了!

四、 源代码:

#include "stdio.h"

#include "string.h"

#define MAX 1000000

char s[MAX];   

int next[MAX];

int main()

{

    freopen("1.txt","r",stdin);

    int i, j, len;

 

    while (scanf("%s", s) != NULL)

    {

        if (s[0] == '.' && s[1] == '/0')

        {

            break;

        }

 

        len = strlen(s);

        i = 0;

        j = -1;

        next[0] = -1;

        while (i < len)

        {

            if (j == -1 || s[i] == s[j])

            {

                ++i;

                ++j;

                if (s[i] != s[j])

                {

                    next[i] = j;

                }

                else

                {

                    next[i] = next[j];

                }

            }

            else

            {

                          j = next[j];

            }

        }

        i -= j;

        if (len % i == 0)

        {

            i = len / i;

        }

        else

        {

            i = 1;

        }

        printf("%d/n", i);

    }

 

    return 0;

}

五、Memory: 3108K Time: 110MS

六、总结:

    在平时的学习过程中,就应该培养对每一个知识点搞明白!反正现在是读大学了,已经远离应试教育的折磨了;学东西就要将自己感兴趣的学好!

 

 

 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值