c语言最长公共子序列_【面试】动态规划-之最长公共子序列、最长公共子串问题

12df4372a5969ea0095ef93e1f0b17b4.png

先来说明下什么是最长公共子序列,什么是是最长公共子串,举一个实际例子,myblogs与belong,最长公共子序列为blog(myblogs, belong),最长公共子串为lo(myblogs, belong)也就是说子串要求在原字符串中是连续的,而最长公共子序列则并不要求连续。

最长公共子序列问题

问题描述

给两个字条串X="ABCBDAB",Y="BDCABA",求这两个字符串的最长公共子序列。

问题分析

这里只求这个公共子序列的长度。 利用动态规划的思想分析。 定义一个前缀概念:

给定一个序列X = <x1,x2 ,..., xm>,对于i = 0,1,...,m,定义X的第i前缀为Xi = <x1,x2 ,..., xi>。例如,若 X = <A,B,C,B,D,A,B>,则 X4 = <A,B,C,B>,X0为空串。

则减小问题的规模,X、Y都去掉一个字符时,他们的最长公共子串和X与Y的最长公共子串有什么关系呢?

X = <x0,x1,x2 ,...>Y = <y0,y1,y2 ,...> 为两个序列,Z =<z0,z1,z2 ,...为X和Y的任意LCS。c[i,j]表示Xi和Yj的LCS的长度,则: - 如果Xi = Yj,则 c[i,j]=c[i-1,j-1]+1。 - 如果 Xi ≠ Yj,则 c[i,j]=max(c[i-1,j],c[i,j-1])

此时要求i>0,j>0,即X、Y的字符个数都至少为两个,因为上面的递推公式都用到了c[i-1,j-1]

考虑初始条件,如果X,Y有一个为空串,则就没有公共子序列了。

如果X,Y有一个为只含一个字符的子符串,则公共子串要么是没有,可以看成是长度为0,要么是就是这个字符了其长度为1.

按这个思路,先计算初始条件,然后利用递推公式计算所有值,代码实现如下。

代码实现

int lcs(string word1, string word2) {
    int size1 = word1.size();
    int size2 = word2.size();

    int max_length=0;
    int dp[size1][size2];

    //初值比较,字符串的第一个字符
    if(word1[0] == word2[0]){
        dp[0][0] =1;
        max_length = 1;
    }else{
        dp[0][0] =0;
    }

    //字符串word2的一个字符,各word1的所有字符
    for(int i = 1,j=0; i<size1; i++){
        if(word1[i] == word2[j]){
            dp[i][j] = 1;
            max_length = 1;
        }else{
            dp[i][j] = dp[i-1][j];
        }
    }

    //字符串word1的一个字符,各word2的所有字符
    for(int j=1,i=0; j<size2; j++){
        if(word1[i] == word2[j]){
            dp[i][j] = 1;
            max_length = 1;
        }else{
            dp[i][j] = dp[i][j-1];
        }
    }

    //利用上面的初始化值来迭代
    for(int i =1; i<size1; i++){
        for(int j=1; j<size2;j++){
            dp[i][j] =0;

            if(word1[i] == word2[j]){
               dp[i][j] = dp[i-1][j-1] +1;
            }else{
               dp[i][j] = max(dp[i-1][j],dp[i][j-1]);
            }

            if(dp[i][j] > max_length ){
                max_length = dp[i][j] ;
            }
        }
    }

    return max_length;
}

最长公共子串问题

这里以leetcode上的一个最长公共子数组问题来说明。

问题描述

给数组A,B,求A,B的最长公共子数组,如 Input: A: [1,2,3,2,1] B: [3,2,1,4,7] Output: 3 解释,最长公共子数组为 [3, 2, 1]。

问题分析

和最长公共子序列问题类似,不过c[i][j]定义应该是稍有不同的,这里的c[i][j],表示A[0...i]和B[0...j]的最长公共子串,且此公共子串中一定包含A[i],B[j]的,最长公共子序列中的定义可以不包括A[i],B[j]的。

此时的递推公式也稍有不同了:

  • 如果A[i] = B[j],则 c[i,j]=c[i-1,j-1]+1
  • 如果 A[i] ≠ B[j],则 c[i,j]=0

代码实现

int findLength(vector<int>& A, vector<int>& B) {
    int asize=A.size();
    int bsize=B.size();
    int dp[asize][bsize];
    int max = 0;

    for(int i=0,j=0; i<asize; i++){
        if(A[i] == B[j]){
            dp[i][j] = 1;
            max = 1;
        }else{
            dp[i][j] = 0;
        }
    }

    for(int i=0,j=0; j<bsize; j++){
        if(A[i] == B[j]){
            dp[i][j] = 1;
            max = 1;
        }else{
            dp[i][j] = 0;
        }
    }

    for(int i=1; i<asize; i++){
        for(int j = 1; j<bsize; j++){
            if(A[i] == B[j]){
                dp[i][j] = dp[i-1][j-1] + 1;
            }else{
                dp[i][j] = 0;
            }

            if(dp[i][j] > max){
                max = dp[i][j];
            }
        }
    }

    return max;
}

todo: - 补充c数组的表格 - 加求具体序列的方法

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值