题目
问题描述
小R正在研究DNA序列,他需要一个函数来计算将一 个受损DNA序列 (dna1) 转换成一个未受损序列 (dna2) 所需的最少编辑步骤。编辑步骤包括:增加一个碱基、删除一个碱基或替换一个碱基。
测试样例
样例1:
输入:
dna1 = "AGT", dna2 = "AGCT"输出:1
样例2:
输入:
dna1 = "AACCGGTT", dna2 = "AACCTTGG"输出:4
样例3:
输入:
dna1 = "ACGT", dna2 = "TGC"输出:3
样例4:
输入:
dna1 = "A", dna2 = "T输出:1
样例5:
输入:
dna1 = "GGGG", dna2 = "TTTT输出:4
解题思路
思想:动态规划
写在前面:对给定数组的一个调整,在dna1和dna2的第0个位置插入一个占位符,为了使后面dp数组的含义更符合我自己的习惯与理解,因此dna1[1,n]和dna2[1,m]是有效的字符。
状态转移
dp[i][j]表示dna1[1,i]通过三种操作变为dna2[1,j]的最小次数。
分为以下情况:
-
当
dna1[i] == dna2[j]时,不操作,只要延续前面的状态即可,所以有dp[i][j] = dp[i-1][j-1]。 -
当
dna1[i] != dna2[j]时,需要操作,在以下三种操作中取最小值:- 在
dna1中删除字符dna1[i]:dp[i][j] = dp[i-1][j] + 1; - 在
dna1中增添字符dna2[j]:等价于在dna2中删除字符dna2[j]:dp[i][j] = dp[i][j-1] + 1; - 在
dna1中修改字符dna1[i]:等价于要让dna1[i] == dna2[j]:dp[i][j] = dp[i-1][j-1] + 1。
- 在
由于dp[i][j]的状态是由dp[i-1][j-1], dp[i-1][j], dp[i][j-1]得到,因此遍历顺序为:从左到右、从上到下。
初始化
- 显然,当两个
dna都为空的时候,不需要任何操作,因此有dp[0][0] = 0;
dp[i][0]表示将一个长度为i的dna删空的操作数,因此有dp[i][0] = i;
dp[0][j]表示将一个空的dna增添字符成为一个长度为j的dna的操作数,因此有dp[0][j] = j。
Code
#include <iostream>
#include <string>
#include <vector>
int solution(std::string dna1, std::string dna2) {
int len1 = dna1.size(), len2 = dna2.size();
dna1 = "." + dna1;
dna2 = "." + dna2;
std::vector<std::vector<int>> dp(len1+1, std::vector<int>(len2+1, 0));
for (int i = 1; i <= len1; i++) dp[i][0] = i;
for (int j = 1; j <= len2; j++) dp[0][j] = j;
for (int i = 1; i <= len1; i++) {
for (int j = 1; j <= len2; j++) {
if (dna1[i] == dna2[j]) dp[i][j] = dp[i-1][j-1];
else dp[i][j] = std::min(dp[i-1][j] + 1, std::min(dp[i][j-1] + 1, dp[i-1][j-1] + 1));
}
}
return dp[len1][len2];
}
int main() {
// You can add more test cases here
std::cout << (solution("AGCTTAGC", "AGCTAGCT") == 2) << std::endl;
std::cout << (solution("AGCCGAGC", "GCTAGCT") == 4) << std::endl;
return 0;
}
复杂度分析
时间复杂度分析
- 初始化
dp数组时,我们需要将dp[i][0]设置为i,dp[0][j]设置为j,这两个操作的时间复杂度是 O(m + n),其中m和n分别是dna1和dna2的长度。 - 然后,遍历
dp数组的每个元素并计算dp[i][j],这一步的时间复杂度是 O(m * n),因为我们需要填充m * n个位置。
因此,整体的时间复杂度为: O(m * n) ,其中 m 和 n 分别是 dna1 和 dna2 的长度。
空间复杂度分析
空间复杂度主要由 dp 数组的大小决定。我们使用了一个二维数组 dp,其大小为 (m + 1) * (n + 1),所以空间复杂度为: O(m * n)
总结
- 时间复杂度:
O(m * n),其中m是dna1的长度,n是dna2的长度。 - 空间复杂度:
O(m * n),用于存储dp数组。