求两个字符串的最长子序列

方法:动态规划.
循环遍历两个字符串,查找当s1[i]==s2[k] 的情况 然后保存在c[i][k]中,c[i][k]=c[i-1][k-1]+1 最后我们会得到类似以下矩阵

 

    #include <stdio.h>  
    #include <stdlib.h>  
    #include <string.h>  
    //求公共子串(连续),注意跟求公共子序列有区别  
    int lcstr( const char* s1,const char* s2)  
    {  
        //clen保存公共子串的最大长度,s1_Mindex保存 s1公共子串的最后一个元素的位置  
        int len1,len2,i,k,cLen=1,s1_Mindex=0;  
        int **c;  
        if(s1==NULL || s2==NULL) return -1;  
        len1=strlen(s1);  
        len2=strlen(s2);  
        if(len1< 1 || len2 < 1) return -1;  
        c=malloc(sizeof(int*)*len1);  
        for(i=0;i<len1;i++)  
        {  
            c[i]=(int *)malloc(len2*sizeof(int));  
            memset(c[i],0,len2*sizeof(int));  
        }  
        /**********init end!*************/  
        for(i=0;i<len1;i++)  
        {  
            for(k=0;k<len2;k++)  
            {  
                if(i==0 || k==0)  
                {  
                    if(s1[i]==s2[k]) c[i][k]=1;  
                    else c[i][k]=0;  
                }  
                else  
                {  
                    if (s1[i] == s2[k])  
                    {  
                        c[i][k] = c[i - 1][k - 1] + 1;  
                        if (cLen < c[i][k])  
                        {  
                            cLen = c[i][k];  
                            s1_Mindex = i;  
                        }  
                    }  
                }  
            }  
        }  
        //*************//  
        // printf the one of lcs 只是其中一条,如果存在多条。  
        for(i=0;i<cLen;i++)  
        {  
            printf("%c",*(s1+s1_Mindex-cLen+1+i));  
        }  
        /*****free array*************/  
        for(i=0;i<len1;i++)  
            free(c[i]);  
        free(c);  
        return cLen;  
      
    }  
    int main(void) {  
        char a[]="abcgooglecba";  
        char b[]="cbagoogleABVC";  
        printf("\nlcstr = %d\n",lcstr(a,b));  
        return 0;  
    }  
 用一维数组实现:
<pre name="code" class="cpp">#include<string.h>
#define M 100
 
//LCS问题就是求两个字符串最长公共子串的问题
char* LCS(char left[],char right[])
{  
    //获取左子串的长度,获取右子串的长度
    int lenLeft=strlen(left),lenRight=strlen(right),k;
    //注意这里要写成char型,而不是int型,否则输入整型数据时会产生错误。
    //矩阵c纪录两串的匹配情况
    char*c=malloc(lenRight),*p;     
        //int c[M][M]={0};//当将c申明为一个二维数组时
    int start,end,len,i,j;//start表明最长公共子串的起始点,end表明最长公共子串的终止点
    end=len=0;//len表示最长公共子串的长度
 
    for(i=0; i<lenLeft; i++) //串1从前向后比较
    {
        //串2从后向前比较,为什么要从后向前呢?是把一维数组c[ ]当二维数组来用,
        //如果要从前向后,可以将c申明为一个二维数组c[M][M].但程序要做相应调整.
        // for(j=0;j<lenRight;j++)//当c申明为一个二维数组时
        for(j=lenRight-1; j>=0; j--)
        {
            if(left[i] == right[j])//元素相等时
            {
                if(i==0||j==0)
                    c[j]=1;//c[i][j]=1;
                else
                {
                    c[j]=c[j-1]+1;//c[i][j]=c[i-1][j-1]+1;
                }
            }
            else
                c[j] = 0;    //c[i][j]=0;
            if(c[j] > len)   //if (c[i][j]>len)
            {
                len=c[j];   //len=c[i][j];
                end=j;
            }
        }
    }
    start=end-len+1;
     
    //数组p纪录最长公共子串
    p =(char*)malloc(len+1);
    for(i=start; i<=end; i++)
    {
        p[i-start] = right[i];
    }
    p[len]='\0';
    return p;
}
 
void main()
{
    char str1[M],str2[M];
    printf("请输入字符串1:");
 
    gets(str1)
    printf("请输入字符串2:");
 
    gets(str2);
    printf("最长子串为:");
 
    printf("%s\n",LCS(str1,str2));
 
}

程序测试:

输入

字符串1:21232523311324

字符串2:312123223445

数组c的变化情况为:

0 0 1 0 1 0 1 1 0 0 0 0

0 1 0 2 0 0 0 0 0 0 0 0

0 0 2 0 3 0 1 1 0 0 0 0

1 0 0 0 0 4 0 0 2 0 0 0

0 0 1 0 1 0 5 1 0 0 0 0

0 0 0 0 0 0 0 0 0 0 0 1

0 0 1 0 1 0 1 1 0 0 0 0

1 0 0 0 0 2 0 0 2 0 0 0

1 0 0 0 0 1 0 0 1 0 0 0

0 2 0 1 0 0 0 0 0 0 0 0

0 1 0 1 0 0 0 0 0 0 0 0

1 0 0 0 0 1 0 0 1 0 0 0

0 0 1 0 1 0 2 1 0 0 0 0

0 0 0 0 0 0 0 0 0 1 1 0

长:14(串1的长度),宽:12(串2的长度)

最长子串为:21232

评论:该算法只能打印出最长公共子串中的一个,而不是全部解.


 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值