kmp的中的next数组的应用

链接:https://ac.nowcoder.com/acm/contest/2272/F
来源:牛客网

帕秋莉掌握了一种水属性魔法

这种魔法可以净化黑暗

帕秋莉发现对于一个黑暗的咒语s,可以使用这个水元素魔法净化它,净化的咒语是一个最长的字符串t,t满足以下条件:

它是s的前缀

它是s的后缀

除前缀和后缀外,它还在s中出现过至少一次

既然你都学会了,那么净化的工作就交给你了!

输入描述:

一行字符串 s ,代表黑暗咒语

输出描述:

一个字符串 t ,表示满足条件的最长净化咒语
示例1

输入

复制
tqrwantoacthisproblembutqristooweaktodoitqr

输出

复制
tqr

备注:

对于60%的数据,s长度≤100
对于100%的数据,s长度≤100,000
保证存在可行的净化咒语


kmp的next数组的应用:
首先你要知道next数组的含义:就是最长公共前后缀。

KMP算法中,求了一个前缀函数: 为前  个字符组成的子串中、真前缀、真后缀相等的最大长度。

例如对于abcabcd

  1. a,,没有真前后缀。
  2. ab,
  3. abc,
  4. abca,
  5. abcab,
  6. abcabc,
  7. abcabcd,

目标函数最长的公共前后缀就是next[len],但是还要满足一个条件,就是在在这个串中还要出现这个字串,

怎么判断他还出现过呢,就是1到n-1的next[i]都标记上,f[next[temp]==1,符合条件,否者temp=next[temp],他不能等于temp-1,举个例子就知道了

#include<iostream>
#include<algorithm>
#include<cstring> 
using namespace std;
const int maxn=1e6+100; 
char a[maxn];
int f[maxn];
int ne[maxn];
int n; 
void getnext(int m){
    int i=0,j=-1;
    int len=m;
    ne[0]=-1;
    while(i<len){
        if(j==-1||a[i]==a[j]){
            i++;
            j++; 
            ne[i]=j;
        }
        else{
            j=ne[j];
        }
    } 
}
int main(){
    scanf("%s",a); 
    n=strlen(a);
    getnext(n); 
    for(int i=0;i<=n-1;i++){
        f[ne[i]]=1;
    }
    int temp=n;
    while(ne[temp]){
        if(f[ne[temp]]){
            for(int i=0;i<ne[temp];i++){
                printf("%c",a[i]);
            }
            return 0;
        }
        temp=ne[temp];
    }
    return 0;
} 

 

 

 

这样也是可以的

#include <bits/stdc++.h>
using namespace std;
const int N = 100100;
int nex[N];
void get_next(char *p){
    int len = strlen(p);
    nex[0] = -1;
    int i = 0, k = -1;
    while (i < len){
        if(k == -1 || p[i] == p[k]){
            i++;
            k++;
            nex[i] = k;
        }
        else k = nex[k];
    }
}
int net[N];
int kmp(char *a, char *b){
    int lena = strlen(a);
    int lenb = strlen(b);
    int i = 0, k = 0;
    int res = 0;
    while (i < lena && k < lenb){
        if(k == -1 || a[i] == b[k]){
            ++i, ++k;
        }
        else k = nex[k];
        if(k == lenb){
            k = nex[k];
            res++;
        }
    }
    return res;
}
char s[N];
int main()
{
    scanf("%s", s);
    get_next(s);
    int k = nex[strlen(s)];
    int res = 0;
    char t[N];
    while (k != -1){
        int i;
        for (i = 0; i < k; i++)t[i] = s[i];
        t[i] = '\0';
        res = kmp(s, t);
        if(res >= 3)break;
        k = nex[k];
    }
    printf("%s\n", t);
    return 0;
}

 

posted @ 2021-01-17 18:34  lipu123  阅读(131)  评论(0编辑  收藏  举报