原题地址:DNA序列编辑距离 - MarsCode
问题描述
小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
步骤一:初始化相关变量及边界条件
收起
java
复制
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;
}
for (int j = 0; j <= n; j++) {
dp[0][j] = j;
}
-
首先获取两个输入 DNA 序列字符串
dna1和dna2的长度,分别赋值给变量m和n。 -
接着创建了一个二维数组
dp,其维度为(m + 1)×(n + 1)。这个dp数组用于存储动态规划过程中的中间结果,其中dp[i][j]表示将dna1的前i个字符转换为dna2的前j个字符所需要的最少编辑次数。 -
然后通过两个
for循环来初始化dp数组的边界条件:- 当
dna2的长度为 0(也就是j = 0)时,要将dna1的前i个字符转换为dna2(空字符串),唯一的操作就是删除dna1中的这i个字符,所以dp[i][0] = i,即需要进行i次删除操作。 - 同理,当
dna1的长度为 0(i = 0)时,要将dna1(空字符串)转换为dna2的前j个字符,就需要进行j次插入操作,所以dp[0][j] = j。
- 当
步骤二:填充动态规划数组
收起
java
复制
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(dp[i - 1][j - 1], Math.min(dp[i - 1][j], dp[i][j - 1])) + 1;
}
}
}
这里使用了两层嵌套的 for 循环来填充 dp 数组的其余部分(除去已经初始化的边界部分),循环变量 i 和 j 分别从 1 开始遍历到 dna1 和 dna2 的长度 m 和 n。对于每个 dp[i][j]:
-
如果
dna1的第i个字符(索引为i - 1,因为字符串索引从 0 开始)和dna2的第j个字符相等,这意味着不需要进行任何编辑操作,此时将dna1的前i个字符转换为dna2的前j个字符所需的最少编辑次数,就等于将dna1的前i - 1个字符转换为dna2的前j - 1个字符所需的最少编辑次数,即dp[i][j] = dp[i - 1][j - 1]。 -
如果这两个字符不相等,那么就需要考虑三种可能的编辑操作来使得它们相等,并选择其中操作次数最少的情况再加 1(因为进行了一次编辑操作):
-
dp[i - 1][j - 1]:表示替换操作,即将dna1中当前位置(第i个)的字符替换为dna2中当前位置(第j个)的字符,所以编辑次数基于将dna1的前i - 1个字符转换为dna2的前j - 1个字符的最少编辑次数基础上增加 1 次替换操作。 -
dp[i - 1][j]:表示删除操作,即删除dna1中当前位置(第i个)的字符,编辑次数基于将dna1的前i - 1个字符转换为dna2的前j个字符的最少编辑次数基础上增加 1 次删除操作。 -
dp[i][j - 1]:表示插入操作,即在dna1当前位置(第i个)插入一个字符使其与dna2中当前位置(第j个)的字符相等,编辑次数基于将dna1的前i个字符转换为dna2的前j - 1个字符的最少编辑次数基础上增加 1 次插入操作。
-
通过 Math.min 函数选取这三种情况中编辑次数最少的那种情况,然后再加 1,就得到了 dp[i][j] 的值,也就是将 dna1 的前 i 个字符转换为 dna2 的前 j 个字符所需的最少编辑次数。
步骤三:返回最终结果
收起
java
复制
return dp[m][n];
当动态规划数组 dp 填充完毕后,dp[m][n] 就表示将整个 dna1 字符串转换为整个 dna2 字符串所需要的最少编辑次数,所以直接返回这个值作为方法的最终结果。