HDU 1238 Substrings

本文解析了HDU1238题目,介绍了如何寻找多个字符串中存在的最长公共子串及其逆序子串的方法。通过KMP算法进行匹配,并提供了完整的C++实现代码。

题目链接:HDU1238

Substrings

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 9192    Accepted Submission(s): 4353


Problem Description
You are given a number of case-sensitive strings of alphabetic characters, find the largest string X, such that either X, or its inverse can be found as a substring of any of the given strings.
 

Input
The first line of the input file contains a single integer t (1 <= t <= 10), the number of test cases, followed by the input data for each test case. The first line of each test case contains a single integer n (1 <= n <= 100), the number of given strings, followed by n lines, each representing one string of minimum length 1 and maximum length 100. There is no extra white space before and after a string. 
 

Output
There should be one line per test case containing the length of the largest string found.
 

Sample Input
  
2 3 ABCD BCDFF BRCD 2 rose orchid
 

Sample Output
  
2 2
 


题意:给出一些字符串,问其中公共的最长子串的长度是多少,这里公共的子串是指子串本身或子串的反串在每个字符串中都出现过。

题目分析:可以先给字符串按长短排好序,然后枚举子串分别用正串和反串进行KMP,取最长的纪录长度。

这里也可以优化一下,比如正串失配再比较反串,KMP的函数可以整合到一起,不通过排序直接找长度最小的处理(不知道能不能变快),不过题目数据太弱了,怎么搞都是0ms,也没啥优化的必要。

//
//  main.cpp
//  HDU1238(1
//
//  Created by teddywang on 16/5/13.
//  Copyright © 2016年 teddywang. All rights reserved.
//

#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
struct str{
    char ss[110];
    int len;
}s[110];
int next1[110],next2[110];
char t1[110],t2[110];
int n,m;

bool cmp(str a,str b)
{
    if(a.len!=b.len)
        return a.len<b.len;
    else
    {
        return strcmp(a.ss,b.ss)<1;
    }
}

void getnext(char *t1,char *t2)
{
    int i=0,j=-1;
    next1[0]=-1;next2[0]=-1;
    int len=strlen(t1);
    while(i<len)
    {
        if(j==-1||t1[i]==t1[j])
        {
            if(t1[++i]==t1[++j])
                next1[i]=next1[j];
            else next1[i]=j;
        }
        else j=next1[j];
    }
    
    i=0;j=-1;
    while(i<len)
    {
        if(j==-1||t2[i]==t2[j])
        {
            if(t2[++i]==t2[++j])
                next2[i]=next2[j];
            else next2[i]=j;
        }
        else j=next2[j];
    }
}

int kmp1(char *s,char *t)
{
    int i=0,j=0;
    int len1=strlen(s),len2=strlen(t);
    while(i<len1&&j<len2)
    {
        if(j==-1||s[i]==t[j])
        {
            i++;j++;
            if(j==len2) return 1;
        }
        else j=next1[j];
    }
    return 0;
}

int kmp2(char *s,char *t)
{
    int i=0,j=0;
    int len1=strlen(s),len2=strlen(t);
    while(i<len1&&j<len2)
    {
        if(j==-1||s[i]==t[j])
        {
            i++;j++;
            if(j==len2) return 1;
        }
        else j=next2[j];
    }
    return 0;
}

int main()
{
    cin>>m;
    while(m--)
    {
        cin>>n;
        for(int i=0;i<n;i++)
        {
            scanf("%s",s[i].ss);
            s[i].len=strlen(s[i].ss);
        }
        sort(s,s+n,cmp);
        int maxlen=0;
        for(int i=0;i<s[0].len;i++)
        {
            int l=0;
            for(int j=i+1;j<=s[0].len;j++)
            {
                int flag=0;
                while(l<j-i)
                    t1[l++]=s[0].ss[i+l];
                for(int k=0;k<l;k++)
                    t2[k]=t1[l-k-1];
                t1[l]=t2[l]='\0';
                getnext(t1,t2);
                for(int k=1;k<n;k++)
                {
                    if(kmp2(s[k].ss,t2)==0&&kmp1(s[k].ss,t1)==0)
                    {
                        flag=1;
                        break;
                    }
                }
                if(flag==1) break;
                else if(l>maxlen)
                    maxlen=l;
            }
        }
        cout<<maxlen<<endl;
    }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值