问题描述:字符串匹配,按照如下方法求出两个字符串的最大匹配位数.
输入:
MARRUPYG
AMTRROPC
输出:
appx(MARRUPYG,AMTRROPC) = 1/2
其中,appx 函数计算公式2个字符串最大匹配字符数*2/(字符串1长度+字符串2长度)
解题思路:
寻找最长公共子序列(Longest Common Subsequence, LCS),子序列不要求字符连续,而子串要求字符连续。
算法思路(最长公共子序列):
-
使用动态规划方法。创建一个二维数组 dp,其中 dpi 表示字符串1的前i个字符和字符串2的前j个字符的最长公共子序列的长度。
-
状态转移:
-
填充完dp数组后,dpm就是最长公共子序列的长度。
-
要得到实际的LCS,我们需要从dp数组的右下角开始回溯。
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
string longestCommonSubsequence(const string& str1, const string& str2) {
int m = str1.length();
int n = str2.length();
// 创建 dp 数组
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 (str1[i-1] == str2[j-1]) {
dp[i][j] = dp[i-1][j-1] + 1;
} else {
dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
}
}
}
// 回溯找出 LCS
string lcs;
int i = m, j = n;
while (i > 0 && j > 0) {
if (str1[i-1] == str2[j-1]) {
lcs = str1[i-1] + lcs;
i--; j--;
} else if (dp[i-1][j] > dp[i][j-1]) {
i--;
} else {
j--;
}
}
return lcs;
}
};
int main() {
Solution solution;
string str1 = "MARRUPYG";
string str2 = "AMTRROPC";
string result = solution.longestCommonSubsequence(str1, str2);
cout << "appx("+str1+","+str2+") = " << double(result.length()*2)/(str1.length()+str2.length()) << endl;
return 0;
}