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

 

转载于:https://www.cnblogs.com/Tang-tangt/p/9295438.html

你可能感兴趣的:(数据结构与算法,面试)