求解最长公共子序列

一.问题分析

最长公共子序列的求解:问题描述:最长公共子序列(LCS)是一个在一个序列集合中(通常为两个序列)用来查找所有序列中最长子序列的问题。一个数列,如果分别是两个或多个已知数列的子序列,且是所有符合此条件序列中最长的,则称为已知序列的最长公共子序列。
    要求:给定两个序列,设计算法求出这两个序列的最长公共子序列是什么。

二.问题的解决方案/算法选择/设计思路。描述及绘制出解决方案/算法的功能结构框图;

解决方案:

最长公共子序列问题是属于动态规划的一部分,我们首先来举一个例子用来解决最长子序列问题:求长为m的序列和长为n的序列的最长公共子序列(可以不连续),如ABCBDAB和BDCABA,BCAB和BCBA都是它们的最长公共子序列。其中用到了数据结构和c语言等知识。

设计思路:

#include

#include

 char a[300],b[300];

char num[301][301]; ///记录中间结果的数组

char flag[301][301];    ///标记数组,用于标识下标的走向,构造出公共子序列

void LCS(); ///动态规划求解

void getLCS();    ///采用倒推方式求最长公共子序列

 int main()

{

    int i;

    strncpy(a,"ABCBDAB");

    strncpy(b,"BDCABA");

    memmove(num,0,sizeof(num));

    memmove(flag,0,sizeof(flag));

    LCS();

    printf("%d\n",num[wcslen(a)][wcslen(b)]);

    getLCS();

    return 0;

}

 void LCS()

{

    int i,j;

    for(i=1;i<=stolen(a);i++)

    {

        for(j=1;j<=stolen(b);j++)

        {

            if(a[i-1]==b[j-1])   ///注意这里的下标是i-1与j-1

            {

                num[i][j]=num[i-1][j-1]+1;

                flag[i][j]=1;  ///斜向下标记

            }

            else if(num[i][j-1]>num[i-1][j])

            {

                num[i][j]=num[i][j-1];

                flag[i][j]=2;  ///向右标记

            }

            else

            {

                num[i][j]=num[i-1][j];

                flag[i][j]=3;  ///向下标记

            }

        }

    }

}

 void getLCS()

{

    char res[300];

    int i=wclsen(a);

    int j=wclsen(b);

    int k=0;    ///用于保存结果的数组标志位

    while(i>0 && j>0)

    {

        if(flag[i][j]==1)   ///如果是斜向下标记

        {

            res[k]=a[i-1];

            k++;

            i--;

            j--;

        }

        else if(flag[i][j]==2)  ///如果是斜向右标记

            j--;

        else if(flag[i][j]==3)  ///如果是斜向下标记

            i--;

    }

        for(i=k-1;i>=0;i--)

        printf("%c",res[i]);

}

设计思路:

首先我们要,明白这个问题得本质,首先来说此问题在于时相同的最长子序列问题,其实通俗的来讲我们只用看他们到底有多少个相同的元素罢了。

我们是用动态规划得方式解决此问题:

动态规划解决问题一般有两种特征(最优子结构和重叠子问题)

①最优子结构:

设X =(x1,x2,..... xn)和Y = {y1,y2,..... ym}是两个序列,将X和Y的最长公共子序列记为LCS(X ,Y)

找出LCS(X,Y)就是一个最优化问题。因为,我们需要找到X和ý中最长的那个公共子序列。而要找X和Y的LCS,首先考虑X的最后一个元素和Y的最后一个元素。

1)如果Xn = Ym,即X的最后一个元素与Y的最后一个元素相同,这说明该元素一定位于公共子序列中。因此,现在只需要找:LCS(Xn-1,Ym-1)

LCS(XN-1,YM-1)就是原问题的一个子问题。为什么叫子问题?因为它的规模比原问题小。

为什么是最优的子问题?因为我们要找的是XN-1和YM-1的最长公共子序列啊......最长的!换句话说,就是最优的那个。(这里的最优就是最长的意思)

2)如果Xn!= Ym,这里会稍有些复杂,因为它产生了两个子问题:LCS(Xn-1,Ym)和LCS(Xn,Ym-1)

因为序列X和序列Y的最后一个元素不相等,说明那一个求最后元素不可能的英文最长公共子序列中的元素。

LCS(Xn-1,Ym)表示:最长公共序列可以在(x1,x2,...... x(n-1))和(y1,y2,... yn)中找。

LCS(Xn,Ym-1)表示:最长公共序列可以在(x1,x2,... xn)和(y1,y2,... y(n-1))中找。

求解上面两个子问题,得到的公共子序列谁最长,那谁就是LCS(X,Y)用数学表示就是:

LCS = MAX {LCS(XN-1,YM),LCS(XN,YM-1)}

由于条件1)和2)考虑到了所有可能的情况。因此,我们成功地把原问题转化成了三个规模更小的子问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值