程序员代码面试指南:
给定两个字符串str1和str2,返回最长公共子序列,存在多个时返回任意一个即可。
动态规划:
str1长度设为M,str2长度设为N,构建dp[M][N]。d[i][j]表示str1[0:i]和str2[0:j]的最长公共子序列的长度。
1.第一列,d[i][0]表示str1[0:i]与str2[0]的最长公共子序列长度,str2只取了一个字符,dp[i][0]最大值是1,如果str1[i]==str2[0],令d[i][0] = 1。一旦d[i][0]设为1,其后的d[i+1:M][0]都为1。
2.第一行同理。
3.其他位置,d[i][j]有三种情况:
(1) d[i-1][j];
(2) d[i][j-1];
(3) 如果str1[i]==str2[j],d[i-1][j-1] + 1;
三者选最大值。
得到dp后,根据dp获取最长公共子序列。
1. 从dp右下角开始,有三种移动方式:向上、向左、向左上。
2. 如果dp[i][j]大于dp[i-1][j]和dp[i][j-1],说明计算dp[i][j]时,选择了dp[i-1][j-1]+1,且str1[i]==str2[j],属于最长公共子序列,向左上方移动;
3. 如果dp[i][j]等于dp[i-1][j]或dp[i][j-1],说明str1[i]不属于最长公共子序列,向左或向上移动。同时等于两者时,可任选其中一个方向。
C++实现如下:
#include <string>
using namespace std;
void getLCS(const string &str1, const string &str2, string &common)
{
if (str1.empty() || str2.empty())
{
return;
}
int **dp = new int*[str1.length()];
for (int i = 0; i < str1.length(); i++)
{
dp[i] = new int[str2.length()];
}
dp[0][0] = (str1.at(0) == str2.at(0) ? 1 : 0);
for (int i = 1; i < str1.length(); i++)
{
if (dp[i - 1][0] == 1)
{
dp[i][0] = 1;
}
else
{
dp[i][0] = (str1.at(i) == str2.at(0) ? 1 : 0);
}
}
for (int j = 1; j < str2.length(); j++)
{
if (dp[0][j - 1] == 1)
{
dp[0][j] = 1;
}
else
{
dp[0][j] = (str1.at(0) == str2.at(j) ? 1 : 0);
}
}
for (int i = 1; i < str1.length(); i++)
{
for (int j = 1; j < str2.length(); j++)
{
dp[i][j] = dp[i - 1][j] > dp[i][j - 1] ? dp[i - 1][j] : dp[i][j - 1];
if (str1.at(i) == str2.at(j))
{
dp[i][j] = dp[i - 1][j - 1] + 1 > dp[i][j] ? dp[i - 1][j - 1] + 1 : dp[i][j];
}
}
}
int m = str1.length() - 1;
int n = str2.length() - 1;
int length = dp[m][n];
char *result = new char[length + 1];
memset(result, 0, (length + 1) * sizeof(char));
int index = length - 1;
while (index >= 0)
{
if (n > 0 && dp[m][n] == dp[m][n - 1])
{
n--;
}
else if (m > 0 && dp[m][n] == dp[m - 1][n])
{
m--;
}
else
{
result[index--] = str1.at(m);
m--;
n--;
}
}
common = result;
delete[] result;
result = NULL;
for (int i = 0; i < str1.length(); i++)
{
delete[] dp[i];
dp[i] = NULL;
}
delete[] dp;
dp = NULL;
}
int main(int argc, char* argv[])
{
string str1 = "1A2C3D4B56";
string str2 = "B1D23CA45B6A";
string common;
getLCS(str1,str2,common);
printf("%s\n", common.c_str());
return 0;
}