HDU4763 Theme Section(KMP+扩展KMP)

题意:给一个字符串S,找出一个最长的子串E,使得S可以写成‘EAEBE’的形式,其中A、B是任意字符串,可空。求E的最大长度。


思路:求前缀和后缀的最大匹配,可以用KMP算法里的next数组;求前缀和中缀的最长匹配,可以用扩展KMP,这里是跟自身匹配,所以搞一次扩展KMP里的求next数组就行了。

考虑到可能中间存在循环节导致中缀匹配的长度大于结果,从后缀匹配的结果入手,对于每个后缀匹配的结果,遍历是否有中缀匹配结果满足,有就输出答案,否则缩小后缀匹配的值继续遍历。


#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<vector>
#include<map>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
const int mod = 1000000007;
const int maxn = 1000005;
typedef long long ll;
int nxt[maxn];
char str[maxn];
int extend[maxn];
void get_extend(char str[]){//扩展KMP
    int i = 0, j, pos;
    int len = strlen(str);
    extend[0] = len;
    while(i + 1 < len && str[i] == str[i + 1]){
        ++i;
    }
    extend[1] = i;
    pos = 1;
    for(i=2; i<len; ++i){
        if(extend[i - pos] < pos + extend[pos] - i){
            extend[i] = extend[i - pos];
        } else {
            j = extend[pos] + pos - i;
            if(j < 0){
                j = 0;
            }
            while(i + j < len && str[i + j] == str[j]){
                ++j;
            }
            extend[i] = j;
            pos = i;
        }
    }
}
void get_next(char s[], int next[]){//KMP算法中的获取next数组
    int len = strlen(s);
    next[0] = -1;
    int index;
    for(int i=1; i<len; ++i){
        index = next[i - 1];
        while(index >= 0 && s[i] != s[index + 1]){
            index = next[index];
        }
        if(s[i] == s[index + 1]){
            next[i] = index + 1;
        } else {
            next[i] = -1;
        }
    }
}
int main(){
    int t;
    scanf("%d", &t);
    while(t--){
        scanf("%s", str);
        get_extend(str);
        int len = strlen(str);
        get_next(str, nxt);
        int tmp = nxt[len - 1], f = 0;
        while(!f && tmp != -1){
            for(int i=0; i<len; ++i){
                if(extend[i] > tmp && tmp < i && i + tmp + tmp + 1 < len){
                    //tmp是后缀匹配的长度减一,此处保证前中后缀不会相互覆盖
                    f = 1;
                    break;
                }
            }
            if(!f){
                tmp = nxt[tmp];
            }
        }
        printf("%d\n", tmp + 1);
    }
    return 0;
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值