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 @   lipu123  阅读(138)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 25岁的心里话
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
历史上的今天:
2020-01-17 乒乓球
点击右上角即可分享
微信分享提示