kmp的中的next数组的应用
链接:https://ac.nowcoder.com/acm/contest/2272/F
来源:牛客网
帕秋莉掌握了一种水属性魔法
这种魔法可以净化黑暗
帕秋莉发现对于一个黑暗的咒语s,可以使用这个水元素魔法净化它,净化的咒语是一个最长的字符串t,t满足以下条件:
它是s的前缀
它是s的后缀
除前缀和后缀外,它还在s中出现过至少一次
既然你都学会了,那么净化的工作就交给你了!
输入描述:
一行字符串 s ,代表黑暗咒语
输出描述:
一个字符串 t ,表示满足条件的最长净化咒语
备注:
对于60%的数据,s长度≤100
对于100%的数据,s长度≤100,000
保证存在可行的净化咒语
kmp的next数组的应用:
首先你要知道next数组的含义:就是最长公共前后缀。
KMP算法中,求了一个前缀函数: 为前 个字符组成的子串中、真前缀、真后缀相等的最大长度。
例如对于abcabcd
a
,,没有真前后缀。ab
,abc
,abca
,abcab
,abcabc
,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; }