940 AlvinZH的最“长”公共子序列
思路
DP,难题。
\(dp[i][j]\) :记录A的前i个字符与B的前j个字符变成相同需要的最小操作数。
初始化:dp[i][0] = i, dp[0][i] = i。分别代表i次删除or添加操作。
三种操作得到dp[i][j],取其中最小值:
- 替换:可能不需要替换,所以是dp[i-1][j-1]+Same(A[i-1],B[j-1]);
- 删除:dp[i-1][j]+1;
- 添加:dp[i][j-1]+1。
千万不要纠结操作的序列是A还是B!
其实这是《算法导论》上一个“编辑距离”问题,比较经典,有兴趣的同学可以看看书or百度看看。
分析
没法分析,DP岂是我等凡人能理解的,sad。
稍微分析,时间复杂度O(n^2)。
参考代码一
//
// Created by AlvinZH on 2017/10/16.
// Copyright (c) AlvinZH. All rights reserved.
//
#include <cstdio>
#include <cstring>
char A[1005], B[1005];
int dp[1005][1005];//记录A的前i个字符转换到B的前j个字符的最小操作数
inline int Same(char a, char b) {
if(a == b) return 0;
else return 1;
}
inline int MIN(int a, int b, int c) {
if(a > b) a = b;
if(a > c) a = c;
return a;
}
int main()
{
while(~scanf("%s %s", A, B))
{
int lenA = strlen(A);
int lenB = strlen(B);
for (int i = 0; i <= lenA; ++i)
dp[i][0] = i;//i次删除操作
for (int i = 0; i <= lenB; ++i)
dp[0][i] = i;//i次添加操作
for (int i = 1; i <= lenA; ++i) {
for (int j = 1; j <= lenB; ++j) {
dp[i][j] = MIN(dp[i-1][j-1]+Same(A[i-1],B[j-1]), dp[i-1][j]+1, dp[i][j-1]+1);
//MIN(替换, 删除, 添加)
}
}
printf("%d\n", dp[lenA][lenB]);
}
}