zoukankan      html  css  js  c++  java
  • 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] = '';
            res = kmp(s, t);
            if(res >= 3)break;
            k = nex[k];
        }
        printf("%s
    ", t);
        return 0;
    }
  • 相关阅读:
    02Hibernate入门
    01Hibernate概述
    ExtJS布局-Layout
    STARLIMS 安装升级解决方案
    Windows Server 2012 安装.Net Framework 3.5
    vim 复制操作
    linux下挂载新硬盘
    转载 更改mysql 数据存储路径
    转载 阿里云centOS防火墙配置
    (转载)java线程
  • 原文地址:https://www.cnblogs.com/lipu123/p/14289748.html
Copyright © 2011-2022 走看看