KMP+hash(好题,对next数组的理解加深)

http://codeforces.com/problemset/problem/126/B-------》》》题目链接

题目大意:

给出一个字符串,找出一个子串既是它的前缀,也是它的后缀,还是一个非后缀也非前缀的子

题目分析:

本来挺简单的一个题,最开始想复杂了,还用了后缀数组,醉了。
这个题主要用的是kmp的next数组,首先我们要了解next数组的定义,next[i]表示以i为末尾的子串的后缀与能够匹配的整个串的最长的前缀。
然后我们可以知道后缀与前缀的最长相同的长度,现在是满足后缀和前缀的最长子串的情况。
然后我们利用hash除了以最后一个字符结尾的情况所有的与前缀匹配的长度。
最后我们利用next数组的性质,如果当前的匹配的长度在hash表中找不到,那么证明不存在非前缀与非后缀的子串符合条件,那么x=next[x],也就是跳转到当前位置失配的重新匹配的位置(免去重复匹配的部分),也就是小于当前情况的最大的子串的后缀和前缀匹配的情况,然后再查hash表。知道找到答案为止,找不到答案证明不存在解。 

自己做的图解:

 如图x2为x1失配时下一步将要用来对比的点,此时说明前缀w1和后缀w2是最长的相同的前后缀,接下来要找有没有既不是前缀也不是后缀的一段,这样就推出x3,原因是如果x3存在,那么前缀w3和后缀w4是最长的相同的前后缀,那么w4就符合要找的那一段,因为它既和前缀w3相同,又和后缀w5相同(原因是w1和w2相同);

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
#include<vector>
#include<cmath>
#include<string>
#include<map>
#include<queue>
using namespace std;
typedef long long ll;
int hash_s[1000001];//hash[i]表示i点存不存在 
char s[1000001];
int next_s[1000001];
//next_s[i]表示点i之前的字符串最长相同的前后缀的前缀的下一个位置 
ll getnext(){
	ll len=strlen(s);
	int i=0,j=-1;
	next_s[0]=-1;
	while(i<len){
		if(j==-1||s[i]==s[j])next_s[++i]=++j;
		else j=next_s[j];
	}
	return len;
}

int main(){
	scanf("%s",s);
	ll len=getnext();
	for(ll i=2;i<len;i++){
		hash_s[next_s[i]]=1;//如果next_s[i]存在,标记 
	}
	//不能把next_s[len]加到hash表中,因为要找字符串中间的一段 
	ll x=next_s[len];
	//如果hash表中不存在next_s[x];
	while(!hash_s[x]&&x){
		x=next_s[x];
	}
	if(!x){
		cout<<"Just a legend";
	}
	else for(int i=0;i<x;i++){
		cout<<s[i];
	}
	cout<<endl;
	return 0;
}
发布了186 篇原创文章 · 获赞 38 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_43746332/article/details/103096294