动态规划(四)最长公共序列

最长公共子序列是动态规划的另一个经典问题:在给定字符串S1和S2,求一个最长的公共子串(不连续)S3,S3同时为S1和S2的子串,且要求它的长度最长,并确定这个长度。

ex:S1为abcfbc  S2为abfcab的最长公共子串S3为 abcb 长度为4

分析:

1、用字符数组S1[n + 1] 和 S2[m + 1] 分别存储长度为n的字符串S1 和 长度为m的字符串S2(S1[0] 和 S2[0]不存储字符,为了方便后边化简子问题)

2、确定状态:(与之前的动态规划不同,状态数组是一个二维数组)dp[n + 1][m + 1]

3、化子问题:dp[i][j]表示以S1[i]结尾字符串和以S2[j]结尾的字符字符串的最长子序列长度(S1[0] S2[0]结尾表示空串)

      ex:S1为abcfbc S2为 abfcab 则dp[2][3]表示字符串ab与字符串abf的最长子序列长度,dp[2][3] = 2

4、确定边界:dp[i][0] = 0(0 <= i <=n)     dp[0][j] = 0(0 <=j <= m),即两个字符串其中一个为空串则最长子序列长度为0

6、状态转移方程,该问题需要一个两层的循环遍历1 <= i <= n,1 <= j <= m

      dp[i][j]取值有两种情况:

      (1)S1[i] = S2[j],即S1中的第i个字符和S2中的第j个字符相同时,此时比存在一个公共子串以S1[i] S2[j]结尾,其他部分等                  价S1中前i - 1个字符和S2中前j - 1个字符的最长公共子串,于是这个子串比dp[i - 1][j - 1]多1,dp[i][j] = dp[i - 1][j - 1] + 1

      (2)S1[i] != S2[j],此时最长公共子串长度为S1中前i - 1个字符和S2中前j个字符的最长公共子串长度S1中前i个字符和S2                 中前j - 1个字符的最长公共子串长度的较大者,dp[i][j] = max{dp[i - 1][j], dp[i][j - 1]}

      综上状态转移方程为:

                  dp[i][j] = dp[i -  1][j - 1] + 1                           S1[i] == S2[j]

                  dp[i][j] = max{dp[i - 1][j], dp[i][j - 1]}           S1[i] != S2[j]

 

                  

#include <iostream>
#include <stdio.h>
#include <cstring>

using namespace std;

char S1[1000];
char S2[1000];
int dp[1000][1000] = {{0, 0}};   //全部初始化为(0, 0),包含临界也初始化完毕

int main(){
    //注意此处,为了方便舍弃字符串的0号位,从1号位开始输入
    while(scanf("%s%s", S1 + 1, S2 + 1) != EOF){
        //注意求字符串长度时也要从1号位开始
        int len1 = strlen(S1 + 1);
        int len2 = strlen(S2 + 1);
        for(int i = 1; i <= len1; i ++){
            for(int j = 1; j <= len2; j ++){
                //两个转换方程
                if(S1[i] == S2[j]){
                    dp[i][j] = dp[i - 1][j - 1] + 1;
                }else{
                    dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
                }
            }
        }
        cout << dp[len1][len2] << endl;
    }
    return 0;
}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值