扩展KMP ( Next数组 )——Simpson's Hidden Talents ( HDU 2594 )

来源:互联网 发布:java生成随机整数 编辑:程序博客网 时间:2024/06/15 08:03
  • 题目链接:
    http://acm.hdu.edu.cn/showproblem.php?pid=2594

  • 分析: 给出两个字符串S1,S2,求出一个最长子串(既是S1 的前缀又是S2的后缀),一开始是打算用完整的扩展KMP去做,但是结果迷之WA,后来改成合并字符串,把S2接S1后面,然后获取整个字符串的Next数组来做。

  • 题解:

    1. 从strlen(s1)的地方开始遍历Next数组,这个时候找S[strlen(s1)]到末尾的后缀与S的前缀的最大匹配,就是题目要求的意思:
    2. L = strlen(s1);for(int i = L; i< l1; i++){    int now = Next[i];    if(i+Next[i] == l1)//如果长度和整个长度相等,那么说明s2的【后缀】和s1的前缀匹配上    {        ans = max(ans , now ) ;//取最大值    }}ans = ans >= L ? L : ans ;//不超过s1的长度
    3. Next数组求法

    4. const int Max=50000+10;int Next[Max*2]; //ex数组即为extend数组void GETNext(char *str){    Clear(Next);    int i=0,j,po,len=strlen(str);    Next[0]=len;//初始化Next[0]    while(str[i]==str[i+1]&&i+1<len)//计算Next[1]        i++;    Next[1]=i;    po=1;//初始化po的位置    for(i=2;i<len;i++)    {        if(Next[i-po]+i<Next[po]+po)//第一种情况,可以直接得到Next[i]的值            Next[i]=Next[i-po];        else//第二种情况,要继续匹配才能得到Next[i]的值        {            j=Next[po]+po-i;            if(j<0)   j=0;//如果i>po+Next[po],则要从头开始匹配            while(i+j<len&&str[j]==str[j+i])//计算Next[i]                j++;            Next[i]=j;            po=i;//更新po的位置        }    }}
  • AC代码:

#include <iostream>#include <cstring>#include <cstdio>#include <queue>#include <algorithm>#include <cmath>#define Clear(a)   memset(a, 0, sizeof(a))using namespace std;const int Max=50000+10;int Next[Max*2]; //ex数组即为extend数组void GETNext(char *str){    Clear(Next);    int i=0,j,po,len=strlen(str);    Next[0]=len;//初始化Next[0]    while(str[i]==str[i+1]&&i+1<len)//计算Next[1]        i++;    Next[1]=i;    po=1;//初始化po的位置    for(i=2;i<len;i++)    {        if(Next[i-po]+i<Next[po]+po)//第一种情况,可以直接得到Next[i]的值            Next[i]=Next[i-po];        else//第二种情况,要继续匹配才能得到Next[i]的值        {            j=Next[po]+po-i;            if(j<0)   j=0;//如果i>po+Next[po],则要从头开始匹配            while(i+j<len&&str[j]==str[j+i])//计算Next[i]                j++;            Next[i]=j;            po=i;//更新po的位置        }    }}char s1[Max*2];char s2[Max*2];int main(){    while(~scanf("%s", &s1) )    {        int L = strlen(s1);        scanf("%s", s1+L);        GETNext(s1);        int l1 = strlen(s1);        int ans = -1;        for(int i = L;i<l1;i++)        {            int now = Next[i];            if(i+Next[i] == l1)            {                ans = max(ans , now ) ;            }        }        ans = ans >= L ? L : ans ;        for(int i=0;i<ans;i++)        {            cout << s1[i];        }        if(ans>=0)        {            cout << " " << ans << endl;        }        else            cout << 0 << endl;    }    return 0;}
0 0