标签:
给定两个字符串str1和str2,返回两个字符串的最长公共子序列。
举例:
str1="1A2C3D4B56",str2="B1D23CA45B6A"
“123456”和"12C4B6"都是最长公共子序列,返回哪一个都行。
经典动态规划,求解二维动态规划表。假设str1的长度为m,str2的长度为n,声明大小为m*n的矩阵dp,行数为m,列数为n。dp[i][j]的含义是str1[0...i]和str2[0...j]的最长公共子序列长度,从左向右,从上到下计算矩阵dp。
具体步骤见《程序员代码面试指南》P210
/*
4.7 给定两个字符串str1和str2,返回两个字符串的最长公共子序列。
*/
#include <iostream>
#include <cstdlib>
#include <vector>
#include <string>
#include <algorithm>
using namespace std;
/*计算动态规划矩阵*/
vector<vector<int>> getDp(string A, string B)
{
if (A.empty() || B.empty())
{
return vector<vector<int>>();
}//if
int aLen = A.size(), bLen = B.size();
/*矩阵dp[i][j]的含义是字符串A[0...i]与字符串B[0...j]的最长公共子序列长度,从左到右,从上到下计算矩阵dp*/
vector<vector<int>> dp(aLen, vector<int>(bLen, 0));
dp[0][0] = A[0] == B[0] ? 1 : 0;
for (int i = 1; i < aLen; ++i)
{
dp[i][0] = max(dp[i - 1][0], A[i] == B[0] ? 1 : 0);
}//for
for (int j = 1; j < bLen; ++j)
{
dp[0][j] = max(dp[0][j], A[0] == B[j] ? 1 : 0);
}//for
for (int i = 1; i < aLen; ++i)
{
for (int j = 1; j < bLen; ++j)
{
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
if (A[i] == B[j])
{
dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
}//if
}//for
}//for
/*此时dp[aLen-1][bLen-1]便是最长公共子序列的长度*/
return dp;
}
/*求最长公共子序列*/
string longestCommonSubsequence(string str1, string str2)
{
if (str1.empty() || str2.empty())
{
return "";
}//if
/*得到最长公共子序列长度的动态规划长度矩阵*/
vector<vector<int>> dp = getDp(str1, str2);
int m = str1.length() - 1, n = str2.length() - 1, len = dp[m][n];
/*最长公共子序列长度为len,初始化一个结果字符串*/
string ret(len,'0');
/*从右下角遍历矩阵*/
for (int idx = len - 1; idx >= 0; )
{
if (n > 0 && dp[m][n] == dp[m][n - 1])
{
/*不选str1[m] 和 str2[n] 向左移动*/
--n;
}//if
else if (m > 0 && dp[m][n] == dp[m - 1][n])
{
/*不选str1[m] 和 str2[n] 向上移动*/
--m;
}//elif
else {
/*选择当前字符,向左上方移动*/
ret[idx--] = str1[m];
--m;
--n;
}//else
}//for
return ret;
}
int main()
{
string str1 = "1A2C3D4B56", str2 = "B1D23CA45B6A";
cout << longestCommonSubsequence(str1, str2) << endl;
system("pause");
return 0;
}GitHub代码标签:
原文地址:http://blog.csdn.net/fly_yr/article/details/51356306