codeforces 126 B. Password KMP算法

题目链接:https://vjudge.net/problem/CodeForces-126B

题意:一个字符串,找出最长的子串t,它既是前缀又是后缀,还出现在中间。输出t,不存在则输出Just a legend。

这个题KMP的next数组的理解还是要有的,next[i]表示在i之前,最长的公共前缀后缀的长度。
所以说,我们首先要看看是否存在公共前缀后缀,如果有,这只是保证了可能有解,因为我们还要看中间是否出现过,这个时候,我们让i=nxt[i],继续看这个nxt[i]是否出现过,为什么呢?因为你此往前移动是,就相当于产生了一个可能的答案,但是我们需要中间也出现过,所以就要判断这个nxt[i]值是否出现过,当出现过的就是答案。

#include<stdio.h>
#include<string.h>
#include<math.h>
#include<string>
#include<vector>
#include<stack>
#include<map>
#include<set>

const int maxn=1000005;
int next[maxn];
int vis[maxn];
char q[maxn];
void  kmp(char w[])
{
    int len=strlen(w);
    int i=0;
    int j=-1;
    next[0]=-1;
    while(i<len) 
    {
        if(j==-1||w[i]==w[j])
        {
            i++;
            j++;
            next[i]=j;
        }
        else j=next[j];  
    }
    for(int i=0;i<len;i++)  ///字符串中的next数组中1——len-1的vis设为1.
    {                        ///表示该next【i】出现过。
        vis[next[i]]=1;     
    }
}

int main()
{
    scanf("%s",q);
    kmp(q);
    int i=strlen(q);
    int flag=1;
    while(next[i]) ///如果最后一个字母的next数组的值为0,则说明没有相同的前缀和后缀,不符题意。
    {
        if(vis[next[i]]) ///如果在next的数值在最后一个字母之前已经出现过,则,说明在中间出现过。
        {
            for(int j=0;j<next[i];j++)
            {
                printf("%c",q[j]);
            }
            flag=0;
            break;
        }
        i=next[i]; ///最长前后缀在中间没出现过,则缩减长度,只能在当前最大前缀中找次最长前缀等于后缀,所以长度就是缩短为next[i]了
    }
    if(flag==0) printf("\n");
    else printf("Just a legend\n");
}

发布了17 篇原创文章 · 获赞 0 · 访问量 117

猜你喜欢

转载自blog.csdn.net/b_o_n_z_t_f/article/details/104702024