题目描述
查找最长的公共子序列
题目描述
实现一个算法查找两个字符串最长的公共子字符串。子字符串的介绍如下:
-
子字符串是指字符串中任意个连续的字符组成的子序列。
输入描述
输入两行,每行一串字符串,长度均不超过 1000。
输出描述
输出一行,为最长公共子序列。
输入输出样例
示例
输入
ASDFGVCVMZKJ
OIKMASDFZCVM
输出
ASDF
运行限制
-
最大运行时间:1s
-
最大运行内存: 256M
题解 1
直接双重循环暴力方法
代码1
#include <algorithm>
#include <cstdint>
#include <iostream>
#include <limits>
#include <set>
#include <utility>
#include <vector>
#include <string>
using namespace std;
int main(){
string str1;
string str2;
cin>>str1;
cin>>str2;
int s1=str1.size();
int s2=str2.size();
int ans=0,t=0,p=0;
for(int i=0;i<s1;i++){
for(int j=0;j<s2;j++){
t=0;
while(str1[i+t]==str2[j+t]){
t++;
if(t>ans){
p=j;
}
}
ans=max(ans,t);
}
}
cout<<str2.substr(p,ans);
return 0;
}
题解2
使用动态规划解法
状态转移方程:
设 dp[i][j]
表示字符串 X[1..i]
和 Y[1..j]
的最长公共子序列的长度。
1.如果 X[i] == Y[j]
,则 dp[i][j] = dp[i-1][j-1] + 1
。
2.如果 X[i] != Y[j]
,则 dp[i][j] = max(dp[i-1][j], dp[i][j-1])
。
3.初始化条件:对于所有的 i
和 j
,dp[i][0] = 0
和 dp[0][j] = 0
。
这三行等式构成了动态规划算法的核心,用于填充一个二维数组 dp
,其中 dp[i][j]
存储了 X
的前 i
个字符和 Y
的前 j
个字符的最长公共子序列的长度。通过这种方式,我们可以避免重复计算子问题,从而有效地解决LCS问题。
代码2:
#include <iostream>
#include <vector>
#include <string>
using namespace std;
// 动态规划求解最长公共子序列问题
string longestCommonSubsequence(string text1, string text2) {
int m = text1.size();
int n = text2.size();
vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
// 构建DP表
for (int i = 1; i <= m; ++i) {
for (int j = 1; j <= n; ++j) {
if (text1[i - 1] == text2[j - 1]) {
dp[i][j] = dp[i - 1][j - 1] + 1;
} else {
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
}
}
}
// 从DP表中回溯找出LCS
string lcs;
int i = m, j = n;
while (i > 0 && j > 0) {
if (text1[i - 1] == text2[j - 1]) {
lcs = text1[i - 1] + lcs;
--i;
--j;
} else if (dp[i - 1][j] > dp[i][j - 1]) {
--i;
} else {
--j;
}
}
return lcs;
}
int main() {
string str1, str2;
cin >> str1 >> str2;
cout << longestCommonSubsequence(str1, str2) << endl;
return 0;
}