【郭炜老师】【动态规划】3.最长公共子序列LCS(POJ 1458)

含义:

        给出两个字符串,求出这样的1个最长的公共子序列的长度:子序列中的每个字符都应在原串中找到每个字符的先后顺序和原串中的先后顺序一致

举个栗子:

        如(abcfbc 和 abfcab两个串,左边为串s1,右边为串s2,则” abc “为他们当中的一个子序列,且符合上面我所讲的条件。且 “ abcb ”也是当中的一个子序列,字符可以在原串中找到,且先后顺序相同。“ abcb ”是其中一个最长公共子序列。他的长度是4)。

POJ 1458 Common Subsequence:

        题目要求:给两个子串s1,s2,求s1和s2的最长公共子序列的长度。

思路:

       1.输入两个子串s1,s2,。(字符从0开始输入)

       2.用 MaxLen(i , j )表示s1前 i个字符形成的子串与s2前  j 个字符形成的子串的最长公共子序列的长度。(牢记这句话)、

              显然,假设s1串长为length1,s2串长length2,则要求的即为MaxLen(length1,length2).

       3.讨论MaxLen的大小:

              ①。显然,maxLen(n,0)=0,(当n = 0,1,2,3...length1时)。同理maxLen(0,n)=0。(当n = 0,1,2,3,...length2时)。

              ②。其次,当s1[ i-1 ] == s2[ j-1 ]时,maxLen(i , j) = maxLen(i-1,j-1)+1。

              【也即s1串的第i-1个字符和s2串的第j-1个字符相同时,他们的最长公共子序列的长度就是原来2个串减1的长度在加上              1,。(因为串从0开始输入,故i-1是串左边的的第 i 个字符。)

              ③。再次,当s1[i-1] != s2[ j-1 ]时,maxLen (i,j) = max(  maxLen(i,j-1),maxLen(i-1,j)  ).

              【也即s1串和s2串最后一个字符不相同时,比较maxLen(i,j-1)和maxLen(i-1,j)的最大值。】

              【(我举个例子,比如(aeb c和abd s,当比较maxLen(4,4)时,最后一个字符c和最后一个字符s不同,故比较maxLen(3,4)和maxLen(4,3),也即比较2和2的大小。选择他们中的较大者。

       4.经过m轮计算,得出结果。即输出最后maxLen(lengh1,length2)

实例解析:

       假设我们来分析串“ abcfbc ” 和串“ abfcab ”的最长公共子序列:

1.设两个子串s1,s2.并输入。

//设两个子串s1和s2
char s1[1000];
char s2[1000];

//设置以i到j的最长子串为maxLength[i][j]
int maxLength[1000][1000];

//输入字符串s1,s2
cin >> s1 >> s2;

 2.易得,maxLength(n,0) = 0和maxLength(0,n) = 0(n=0,1,2,....),这代表一字符串和空串的最长公共子序列,必定为0.。

for(int i=0;i<=length1;i++)
    maxLen[i][0] = 0;
for(int j=0;j<=length2;j++)
    maxLen[0][j] = 0;

3.接下来即可开始考虑,maxLen怎么递推。当最后一个字符相同怎么处理,不同怎么处理。

for(int i=1;i<length1;i++)
{
    for(int j=1;j<length2;j++)
    {
        if(s1[i-1]==s1[j-1]    //这里可能你会有点迷糊,因为字符是从第0开始的,数字i,j代表前i个后后j个子串,故是从1开始的。
            maxLen[i] = maxLen[i-1][j-1] + 1;
        else
            maxLen[i] = max(maxLen[i-1][j],maxLen[i][j-1]);
    }
}
        

         列出一个小图,代表过程。

 

以上为MaxLen数组

时间复杂度分析:O(m*n), m行n列每个maxLen都遍历一遍。

 

下面列出整个代码:

#include <iostream>
#include <cstring>
using namespace std;

char s1[1000];
char s2[1000];
int maxLength[1000][1000];

int main()
{
    while(cin >> s1 >> s2)
    {
        int length1 = strlen(s1);
        int length2 = strlen(s2);
        int i,j;
        for(i=0;i<=length1;i++)
            maxLength[i][0] = 0;
        for(j=0;j<=length2;j++)
            maxLength[0][j] = 0;
        for(i=1;i<=length1;i++)
        {
            for(j=1;j<=length2;j++)
            {
                if(s1[i-1]==s2[j-1])
                    maxLength[i][j] = maxLength[i-1][j-1] + 1;
                else
                    maxLength[i][j] = max(maxLength[i-1][j],maxLength[i][j-1]);
            }
        }

        //test
        for(i=0;i<=length1;i++)
        {
            for(j=0;j<=length2;j++)
                cout << maxLength[i][j]<<"   ";
            cout << endl;
        }

        cout << endl;
        cout << maxLength[length1][length2] << endl;
    }
}

注:我还在代码中列出了test部分,他展示了maxLen[i][j]的变化过程,可以验证我们的计算。submit时记得删除。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值