zoukankan      html  css  js  c++  java
  • 77 最长公共子序列

    原题网址:https://www.lintcode.com/problem/longest-common-subsequence/description

    描述

    给出两个字符串,找到最长公共子序列(LCS),返回LCS的长度。

     

    您在真实的面试中是否遇到过这个题?  

    说明

    最长公共子序列的定义:

    • 最长公共子序列问题是在一组序列(通常2个)中找到最长公共子序列(注意:不同于子串,LCS不需要是连续的子串)。该问题是典型的计算机科学问题,是文件差异比较程序的基础,在生物信息学中也有所应用。
    • https://en.wikipedia.org/wiki/Longest_common_subsequence_problem

    样例

    给出"ABCD" 和 "EDCA",这个LCS是 "A" (或 D或C),返回1

    给出 "ABCD" 和 "EACB",这个LCS是"AC"返回 2

    标签
    最长公共子串
    LintCode 版权所有
    动态规划(DP)

     

    思路:动态规划。创建二维数组dp【m+1】【n+1】,并初始化元素值为0。dp【i】【j】表示 A 串 0~i-1 与 B 串 0~j-1 的LCS。

    状态转移方程:

    固定一个字符串,遍历另一个字符串,如果A【i-1】==B【j-1】,dp【i】【j】=dp【i-1】【j-1】+1;

    否则,说明 A【i-1】和 B【j-1】不可能是最长公共子序列中的元素,所以应在A 串 0~i-1 与 B 串 0~j-2 或 A 串 0~i-2 与 B 串 0~j-1 中寻找LCS,二者中较大者即为dp【i】【j】。即 dp【i】【j】= max(dp【i】【j-1】,dp【i-1】【j】);

    最后返回dp【m】【n】,A 串 0~m-1 与 B 串 0~n-1 的LCS。

    【状态转移方程是递增或者不变的,所以后面位置的LCS一定大于或者等于前面位置的,所以最后一个元素一定是两个字符串的LCS最大值。】

     

    AC代码:

    class Solution {
    public:
        /**
         * @param A: A string
         * @param B: A string
         * @return: The length of longest common subsequence of A and B
         */
        int longestCommonSubsequence(string &A, string &B) {
            // write your code here
        if (A.size()==0||B.size()==0)
         {
             return 0;
         }
         int n1=A.size(),n2=B.size();
         vector<vector<int>> dp(n1+1,vector<int>(n2+1,0));
         for (int i=1;i<=n1;i++)//小于等于;
         {
             for (int j=1;j<=n2;j++)
             {
                 if (A[i-1]==B[j-1])
                 {
                     dp[i][j]=dp[i-1][j-1]+1;
                 }
                 else
                 {
                     dp[i][j]=max(dp[i-1][j],dp[i][j-1]);
                 }
            
             }
         }
         return dp[n1][n2];
        
        }
    };

     

    动态数组大小为A.size()+1 × B.size()+1 , dp【i】【j】表示 A 串 0~i-1 与 B 串 0~j-1 的LCS 而不是 A 串 0~i 与 B 串 0~j 是为了计算方便,如果是后者,需要先计算dp数组的第一行和第一列,代码复杂度增加。

     

    参考:

    经典算法——最长公共子序列  与 求解两个字符串的最长公共子序列  讲解详细易懂

    其中链接2摘抄部分原文如下,并添加绿字以便更好的理解:

     

    二,算法求解

     

    这是一个动态规划的题目。对于可用动态规划求解的问题,一般有两个特征:①最优子结构;②重叠子问题

     

    ①最优子结构

     

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

     

    找出LCS(X,Y)就是一个最优化问题。因为,我们需要找到X 和 Y中最长的那个公共子序列。而要找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)  考虑到了所有可能的情况。因此,我们成功地把原问题 转化 成了 三个规模更小的子问题

     

     

    动态规划基础篇之最长公共子序列问题

    最长公共子序列

    https://blog.csdn.net/ljlstart/article/details/48350223

     

    PS:最开始想到了动态规划,然而动态规划数组定义成了一维,还思考了半天怎么计算状态转移方程,用两个字符变量保存字符串上一次相等时的值……后来当然是做不下去了。看了网上答案,要用二维数组,顿时恍然大悟,这种求两个串公共字符的问题当然是二维数组了,题目做的还是不够多,反应不过来。

     

  • 相关阅读:
    寒假学习进度8
    寒假学习进度7
    寒假学习进度6
    寒假学习进度5
    寒假学习进度4
    寒假学习进度3
    寒假自学进度13
    Python引用某一文件的方法出现红色波浪线
    寒假自学进度11
    正则表达式(学习)
  • 原文地址:https://www.cnblogs.com/Tang-tangt/p/9295438.html
Copyright © 2011-2022 走看看