回 帖 发 新 帖 刷新版面

主题:第41次编程比赛之主打题

求两个字符串的最长公共子串的长度

若有字符串s1,s2,cs, 其中cs既是s1的子串也是s2的子串, 则cs被称作为s1和s2的公共子串,比如
s1 = "abcdefg"
s2 = "xadzfcy" 
则"adf"是s1和s2的公共子串,"ac"是另外一个公共子串, "adfc"则不是公共子串

假设一个公共子串cs的长度为len, 并且我们找不到长度大于len的公共子串, 那么cs可以被称为是s1和s2的最长公共子串, len就是最长公共子串的长度. 上例中, s1和s2的最长公共子串为"adf", 最长公共子串的长度为3

注意两个字符串的最长公共子串有可能有多个, 
s1 = "ab"
s2 = "ba"
字符串"a" 和"b"都是s1和s2的最长公共子串,但是最长公共子串的长度只有一个, 就是1

请编写程序求给定两个字符串的最长公共子串的长度, 函数原型为
int LCS(char* str1, char* str2);



测试环境
    P3M 1.2G 640MB  
    visual studio 2002, release mode
    运行时间为10s, 字符串长度最长20000, 如果大家程序都比较快,我会继续增加字符串的长度

本次比赛截止时间为星期六下午一点整,到时间后我会另开一贴供大家提交自己的测试数据, 到星期天晚上七点截止. 这些数据和我自己的数据都会被用来测试大家提交的程序.

回复列表 (共14个回复)

11 楼





int LCS(char *str1,char *str2)
{
   char s1[20000],c2[20000],*cp1,*cp2,*cp;
    cp1=s1;cp2=s2;
   int k=0,t=0,max;
   for(;*str1!='\0';str1++)
     for(;*str2!='\0';str2++)
        {if(*str1==*str2)
            {*cp1=*str1;cp1++;k++;}
           else
              continue;
        }
       *cp1='\0';
    for(;*str2!='\0';str2++)
       for(;*str1!='\0';str1++)
       {if(*str1==*str2)
            {*cp2=*str1;cp2++;t++;}
           else
              continue;
        }
       *cp2='\0';
    if(k>t)
      {cp=s1;max=k;}
      else
        {cp=s2;max=t;}
    printf("这两个字符串的最长公共子串是:");
     puts(*cp);
    printf("其长度是%d",max);
}

12 楼

int LCS(char *x, char *y)
{
    int     max = 0;
    int     lenx = strlen(x);
    int     leny = strlen(y);
    int     i, j;
    int     *z;
    char     *p1, *p2;
    int     len1, len2;
    
    if(lenx >= leny)
    {
        len1 = lenx;
        len2 = leny;
        p1 = x;
        p2 = y;
    }
    else
    {
        len1 = leny;
        len2 = lenx;
        p1 = y;
        p2 = x;
    }
    
    z = new int[len2+1];
    assert(z != NULL);
    z[0] = 0;
    
    int    last, temp;
    for(i=1; i<=len1; ++i)
    {
        last = z[0];
        for(j=1; j<=len2; ++j)
        {
            if(p1[i-1] == p2[j-1])
            {
                temp = z[j];
                z[j] = last + 1;
                last = temp;                
                if(z[j] > max)
                    max = z[j];
            }
            else
            {
                last = z[j];
                z[j] = 0;
            }
        }
    }
    
    delete []z;
    
    return max;
}         

// 另一个更快的算法来不及调试通过了。

13 楼

//用c++做的,提交格式不对的请包涵
//复杂度小于O(n`2)吧
#include<iostream>
#include<vector>
#include<cassert>
#define LEN 100
int LCS(char *s1,char *s2);
int Length(int Numbers[],int numbers);
using namespace std;
int LCS(char *s1,char *s2){
    vector<int> Ts1,Ts2;
    char *p1=s1,*p2=s2;
    int i=0,j;
    while(*p1!=NULL||*p2!=NULL){
        Ts2.insert(Ts2.end(),0);
        Ts1.insert(Ts1.end(),0);
        j=0;
        while(j<=i&&*p1!=NULL){
            if(*(s2+j)!=NULL&&*(s2+j)==*p1&&Ts2[j]==0){
                Ts2[j]=i+1;
                Ts1[j]=-1;
                break;
            }
            j++;
        }
        j=0;
        while(j<=i&&*p2!=NULL){
            if(*(s1+j)!=NULL&&*(s1+j)==*p2&&Ts1[j]==0){
                Ts1[j]=i+1;
                Ts2[j]=-1;
                break;
            }
            j++;
        }
        p1++;
        p2++;
        i++;
    }
    int *Buff=new int[i];
    int c=0,res;
    j=0;
    while(j<i){
        if(Ts1[j]>0)
            Buff[c++]=Ts1[j];
        if(Ts2[j]>0)
            Buff[c++]=Ts2[j];
        j++;
    }
    res=Length(Buff,c);//Length做找Buff中最长子数列
    delete Buff;
    return res;
}
int Length(int Numbers[],int nNumbers){//直接找的eastcowboy的O(n*log(n))的算法(:
        assert( nNumbers > 0 );
        /* 尝试采用O(n*log(n))算法 */
        int *buf = new int[nNumbers];
        int i,j;
        int max;

        buf[0] = Numbers[0];
        max = 1;
        for(i=1; i<nNumbers; ++i)
        {
            /* 如果可以在原串中加入,则加入 */
            if( Numbers[i] > buf[max-1] )
            {
                buf[max++] = Numbers[i];
                continue;
            }
            /*
            采用二分查找法在buf中寻找j,
            使得buf[j-1] < Numbers[i] < buf[j]
            定义buf[-1]为无穷小,即:当Number[i] < buf[0]时,j=0
            */
            int low = 0;
            int high = max;
            while( low <= high )
            {
                j = (low+high)/2;
                if( buf[j] == Numbers[i] )
                    break;
                else if( buf[j] < Numbers[i] )
                    low = j + 1;
                else
                    high = j - 1;
            }
            if( buf[j] == Numbers[i] )
                continue;
            j = low;

            /* 修改最长子序列的内容,使之更“优”,可更容易的伸长 */
            buf[j] = Numbers[i];
        }

        delete[] buf;
        return max;
}

14 楼

int LCS(char* str1,char* str2)
{
    int n=strlen(str1);
    int m=strlen(str2);
    int *b=new int[n+1];
    assert(b!=NULL);
    memset(b,0,n+1);
    for(int i=1;i<=m;++i)
    {
        int fw=0;
        for(int j=1;j<=n;++j)
        {
#define MAX(a,b) (a)>(b)?(a):(b)
            int tmp;
            if(str1[i-1]==str2[j-1])
            {
                tmp=fw;
                fw=b[j-1]+1;
                b[j-1]=tmp;
            }
            else
            {
                tmp=fw;
                fw=MAX(fw,b[j]);
                b[j-1]=tmp;
            }
        }
        b[n]=fw;
    }
    int result=b[n];
    if(b)
        delete[]b;
    return result;
}


//希望有更好的算法。。。

我来回复

您尚未登录,请登录后再回复。点此登录或注册