题目描述(京东2020-08-06)
X星人的基因由A、B、C、D、E五种不同的结构组合而成。
如果两个性别不同的X星人的基因序列相似度大于50%,按照X星的法律他们是禁止结婚的,等于50%据说还是可以的。
那么基因的相似度怎么计算呢?分别从两个人身上取长度均为N的基因片段,如果它们的最长公共子序列(注意,最长公共子序列不需要连续)的长度为M,则相似度= M / N。是不是很简单呢?
现在给你两段X星人的基因序列片段,请你判断他们是不是可以结婚?
输入描述
单组输入。
每一组测试数据包含3行:
第1行数字N表示待比较基因序列片段的长度,N<=10-3。
第2行和第3行为两个长度为N的基因序列片段,中间以空格隔开。
输出描述
先输出相似度,结果保留两位小数(四舍五入) ,然后输出判断结果(中间以空格隔开),如果可
以输出"Yes",如果不可以输出"No"。
样例输入
6
A B C D E E
A E D C B B
样例输出
0.33 Yes
题解思路
子序列形式化定义:
给定一个序列X=<x1,x2,x3,x4…,xm>,另一个序列Z=<z1,z2,z3,z4…,zk>,若存在一个严格递增的X的下标序列<i1,i2,i3,…,ik>对所有的1,2,3,…,k,都满足x(ik)=zk,则称Z是X的子序列
比如Z=<B,C,D,B>是X=<A,B,C,B,D,A,B>的子序列
比如说求ABCBDAB和BDCABA的最长公共子序列(LCS): BCAB
- 在对应字符相等的时候,用↖标记(如果箭头是↖,则代表这个字符是LCS的一员,存下来后 i-- , j–)
- 在p1 >= p2的时候,用↑标记(如果箭头是↑ ,则代表这个字符不是LCS的一员,i–)
- 在p1 < p2的时候,用←标记(如果箭头是←,则代表这个字符不是LCS的一员,j–)
如此直到i = 0或者j = 0时停止,最后存下来的字符就是所有的LCS字符
灰色且带↖箭头的部分即为所有的LCS的字符
时间复杂度:
由于只需要填一个m行n列的二维数组,其中m代表第一个字符串长度,n代表第二个字符串长度,所以时间复杂度为O(m*n)
代码示例:
#include <iostream>
#include <vector>
#include <cstdio>
using namespace std;
int main() {
int N;
while (cin >> N) {
vector<char> v1(N);
vector<char> v2(N);
for (int i = 0; i < N; i++) {
cin >> v1[i];
}
for (int i = 0; i < N; i++) {
cin >> v2[i];
}
vector<vector<int>> dp(N + 1, vector<int>(N + 1));
for (int i = 0; i < N; i++) {
for (int j = 0; j < N; j++) {
if (v1[i] == v2[j])
dp[i + 1][j + 1] = dp[i][j] + 1;
else
dp[i + 1][j + 1] = max(dp[i + 1][j], dp[i][j + 1]);
}
}
double res = (double)dp[N][N] / N;
if (res - 0.5 > 1e-10) {
printf("%.2f No", res);
}
else {
printf("%.2f Yes", res);
}
}
return 0;
}
如有不同见解,欢迎留言讨论~~