问题描述
小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
问题理解
这道题要求我们计算将一个受损DNA序列(dna1)转换成一个未受损序列(dna2)所需的最少编辑步骤。编辑步骤包括:增加一个碱基、删除一个碱基或替换一个碱基。
数据结构选择
我们选择使用动态规划(Dynamic Programming, DP)来解决这个问题。动态规划是一种通过将问题分解为子问题并存储子问题的解来解决复杂问题的方法。
算法步骤
-
定义状态:
- 我们使用一个二维数组
dp,其中dp[i][j]表示将dna1的前i个字符转换成dna2的前j个字符所需的最少编辑步骤。
- 我们使用一个二维数组
-
初始化边界条件:
- 当
dna2为空时,将dna1的前i个字符变成空串需要i次删除操作,因此dp[i][0] = i。 - 当
dna1为空时,将空串变成dna2的前j个字符需要j次插入操作,因此dp[0][j] = j。
- 当
-
状态转移方程:
-
如果
dna1的第i个字符和dna2的第j个字符相同,则dp[i][j] = dp[i-1][j-1],即不需要额外的编辑步骤。 -
如果不同,则有三种操作可以选择:
- 删除
dna1的第i个字符:dp[i][j] = dp[i-1][j] + 1 - 插入
dna2的第j个字符到dna1中:dp[i][j] = dp[i][j-1] + 1 - 替换
dna1的第i个字符为dna2的第j个字符:dp[i][j] = dp[i-1][j-1] + 1
- 删除
-
取这三种操作的最小值作为
dp[i][j]的值。
-
-
最终结果:
dp[m][n]即为将dna1转换成dna2所需的最少编辑步骤,其中m和n分别是dna1和dna2的长度。
代码实现
public class Main {
public static int solution(String dna1, String dna2) {
int m = dna1.length();
int n = dna2.length();
int[][] dp = new int[m + 1][n + 1];
// 初始化边界条件
for (int i = 0; i <= m; i++) {
dp[i][0] = i; // 将 dna1 的前 i 个字符变成空串
}
for (int j = 0; j <= n; j++) {
dp[0][j] = j; // 将空串变成 dna2 的前 j 个字符
}
// 填充 DP 表
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= n; j++) {
if (dna1.charAt(i - 1) == dna2.charAt(j - 1)) {
dp[i][j] = dp[i - 1][j - 1]; // 当前字符相同,无需操作
} else {
dp[i][j] = Math.min(
Math.min(dp[i - 1][j], dp[i][j - 1]), // 删除或插入
dp[i - 1][j - 1] // 替换
) + 1;
}
}
}
return dp[m][n];
}
public static void main(String[] args) {
System.out.println(solution("AGCTTAGC", "AGCTAGCT") == 2);
System.out.println(solution("AGCCGAGC", "GCTAGCT") == 4);
System.out.println(solution("AGT", "AGCT") == 1);
System.out.println(solution("AACCGGTT", "AACCTTGG") == 4);
System.out.println(solution("ACGT", "TGC") == 3);
System.out.println(solution("A", "T") == 1);
System.out.println(solution("GGGG", "TTTT") == 4);
}
}
复杂度分析
- 时间复杂度:
O(m * n),其中m和n分别是dna1和dna2的长度。 - 空间复杂度:
O(m * n),用于存储dp数组。
做题心得
- 这道题是编辑距离问题,之前没有学习过,通过这道题学习了一下子序列类型动态规划问题。