最小覆盖子串 KMP

[问题描述]
对于两个字符串x、y, 如果将若干个x 串首尾相连后得到s 串,且y 是s 的子串,那
么我们称x 为y 的覆盖子串。
( 如,将三个abc 首尾相连得到abcabcabc,而bcabcab 是abcabcabc 的子串,所以abc
是bcabcab 的一个覆盖子串)
现在已知字符串y,求y 的最小覆盖子串。
若有多个覆盖子串长度相同,输出字典序最小的一个
[输入格式]
一个字符串y
[输出格式]
输出有两行
第一行输出y 的最小覆盖子串的长度
第二行输出y 的最小覆盖子串
[输入样例]

bcabcab

[输出样例]
3
abc
[样例解释]
见问题描述
[数据范围]
设字符串y 的长度为N
对于30%的数据, N <= 5000
对于100%的数据, N <= 10^6

对于每一个串我们可以求出它的循环节的长度 len-next[len-1] (不懂的自行脑补);

剩下的就是排序了,由于长度可以很大所以我们按开头的位置枚举。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cmath>
#include <queue>
#include <vector>
using namespace std;
char str[2100000];
int next[1100000],n,x;
int getnext()
{
    next[0]=0;
    for(int i=1;i<n;i++)
    {
        int temp=next[i-1];
        while(temp&&str[temp]!=str[i])
            temp=next[temp-1];
        if(str[temp]==str[i])
            next[i]=temp+1;
        else
            next[i]=0;
    }
    int xunhuan = n-next[n-1];
    return xunhuan;
}
bool cmp(int aa,int bb)
{
    for(int i=0;i<x;i++)
    {
        if(str[i+aa]!=str[i+bb])
        {
            return str[i+aa]<str[i+bb];
        }
    }
}
int main()
{
    //freopen("b.in","r",stdin);
    //freopen("b.out","w",stdout);

    scanf("%s",str);
    n=strlen(str);
    int len=getnext();
    printf("%d\n",len);
    for(int i=n;i<=n*2;i++)
    {
        str[i]=str[i-(n/len)*len];
    }
    int  i,j,l;
    i=0;j=1;
	while(i<len && j<len)
	{
		for(l=0;i+l<=2*len&&j+l<=2*len && str[i+l]==str[j+l];++l);
		if(str[i+l]==str[j+l])
			break;
		if(str[i+l]<str[j+l])
            j+=l+1;
		else i+=l+1;
		if(i==j)++j;
	}
	for(l=0;l<len;++l)
		printf("%c",str[l+i]);
    return 0;
}
/*
bcabcab
*/

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值