[每日一题]93:X 星人的基因(动归)

探讨了如何通过计算最长公共子序列来评估X星人基因序列的相似度,以此判断是否符合X星法律允许的婚姻条件。文章详细解释了最长公共子序列的概念,并提供了具体算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目描述(京东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;
}

如有不同见解,欢迎留言讨论~~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值