#include <stdio.h>
#include <cstring>
#include <iostream>
#include <algorithm>
#define max(a,b)a>b?a:b
using namespace std;
int dp[100][100]; // dp[i][j]表示第一个字符串以i结尾第二个字符串以j结尾的最长公共子序列
// 转移方程
// 如果str1[i] == str2[j]时 dp[i][j] = dp[i-1][j-1] + 1;
// str1[i] != str2[j]时 dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
// 初始条件是 dp[0][0~len2] = dp[0~len1][0] = 0;
int vis[100][100];
// 用来标记一下我们找到的子序列的答案
// vis[i][j] 第一个字串以i为结尾第二个字串以j为结尾开始往前找答案
int LCS(char* str1, char* str2) {
int len1 = strlen(str1);
int len2 = strlen(str2);
// 初始化
for (int i = 0; i <= len1; i++) dp[i][0] = 0;
for (int j = 0; j <= len2; j++) dp[0][j] = 0;
for (int i = 1; i <= len1; i++) {
for (int j = 1; j <= len2; j++) {
if (str1[i-1] == str2[j-1]) { // 因为边界不可能小于0
dp[i][j] = dp[i-1][j-1] + 1;
vis[i][j] = 1;
} else {
// dp[i][j] = max(dp[i-1][j], dp[i][j-1]);
if (dp[i-1][j] > dp[i][j-1]) {
dp[i][j] = dp[i-1][j];
vis[i][j] = 2; // 表示是从(i-1, j)->(i, j)的 找字符的时候倒推过去 (i,j)->(i-1,j)
} else {
dp[i][j] = dp[i][j-1];
vis[i][j] = 3;
}
}
}
}
return dp[len1][len2];
}
// 过程表
void show(char* r, char* s) {
printf(" ");
for (int i = 0; i < strlen(s); i++) printf("%c ", s[i]);
printf("\n");
int k = 0;
for (int i = 0; i <= strlen(r); i++) {
if (i >= 1) printf("%c ", r[k++]);
else printf(" ");
for (int j = 0; j <= strlen(s); j++){
printf("%d ", dp[i][j]);
}
printf("\n");
}
printf("\n");
}
void getResult(int i, int j, char* r) {
if (i == 0 || j == 0) return;
if (vis[i][j] == 1) {
getResult(i-1, j-1, r); // 该位置找到了一个字符答案,因为dp[i][j] = dp[i-1][j-1]+1;
printf("%c", r[i-1]);
} else if (vis[i][j] == 2) {
getResult(i-1, j, r); // dp[i][j] = dp[i-1][j];
} else {
getResult(i, j-1, r); // dp[i][j] = dp[i][j-1];
}
}
int main() {
char p[] = {"asdfghj"};
char s[] = {"asdlkdfgh"};
int ans = LCS(p, s);
printf("%d\n", ans);
show(p, s);
getResult(strlen(p), strlen(s), p);
return 0;
}
sincerit LCS最长公共子序列
最新推荐文章于 2018-12-23 23:44:26 发布
