HDU 1841 Find the Shortest Common Superstring(KMP 理解 应用 求组合串的next值判断是否匹配)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1841

表示这个题目做起来还是有点意思的

首先分析一下解这个题目要考虑的两种情况

1、一个串在另外一个串中,那么结果就是两个串中长度长的哪一个

2、一个串的头部是另外一个串的尾部,这里分两种情况(每个串都有一头一尾嘛)

明白上面两点之后开始用KMP解题

首先直观的普通解法是两个串相互前后拼接一次,然后求出next值,最后一个位置的next值,也就是next[len1+len2]

就是两个串最长头尾公共部分(由于后面要讨论串包含关系,所以这里不考虑next[len1+len2]大于位置在前面那个串

的长度

这个完成之后就是判断有没有包含关系了,其实这个也简单,就是短串在长串里面求匹配嘛,对短串求一次next

然后在长串里面匹配一下,看看能否找到匹配就OK了嘛,这样做完全可以,而且复杂度也不高,能通过这个题目

但是这里仅仅要找短串是否在长串里面出现过,如果直接重新求next值,再求匹配,那么先前求的两个串拼接起

来的串的next值就木有用上,那么怎么利用原有的两个拼接串来判断一个串在另外一个串中是否有匹配呢,其实

很简单了,就是判断next[len1*2](len1<len2)之后的next值,如果有next[i]>=len1的那么说明在后面的串部分的i

位置存在一个长度大于等于len1的在i前面的部分和整个串的前缀部分相等,好了,找到了!

其实这样做只是对KMP有一定理解,其实这个题目还是很卡常数的!


#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
#define maxn 1000010
#define MIN(a,b) (a<b?a:b)
#define MAX(a,b) (a>b?a:b)
char str[maxn],rec[maxn],temp[maxn*2];
int next[maxn*2];
int get_next()
{
    int i=0,j=-1;
    next[0]=-1;
    while(temp[i])
    {
        if(j==-1 || temp[i]==temp[j])
        {
            i++,j++;
            next[i]=j;
        }
        else
        j=next[j];
    }
    return 0;
}
bool find_ans(int len1,int len2,int len)
{
    for(int i=len1*2;i<=len;i++)
    if(next[i]>=len1)
    return 1;
    return 0;
}
int main()
{
    int t;
    int len1,len2,len,ans;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%s%s",str,rec);
        len1=strlen(str);
        len2=strlen(rec);
        len=len1+len2;
        ans=len;
        strcpy(temp,str);
        strcpy(temp+len1,rec);
        get_next();
        ans=len-next[len];// 这里不需要做特殊判断,如果两个串有包含关系后面会检测出来
        if(len1 <=len2)
        {
            if(find_ans(len1,len2,len))
            {
                printf("%d\n",MAX(len1,len2));
                continue;
            }
        }
        strcpy(temp,rec);
        strcpy(temp+len2,str);
        get_next();
        if(len2<=len1)
        {
            if(find_ans(len2,len1,len))
            {
                printf("%d\n",MAX(len1,len2));
                continue;
            }
        }
        ans=MIN(ans,len-next[len]);
        printf("%d\n",ans);

    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值