题目描述
小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长度分别为n和m。
- 定义dp[i][j]为将dna1中的前i个字符转换为dan2的前j个字符所需要的最小操作次数
- dp数组的大小定义为dp[n+1][m+1],因为我们最终需要返回的数据为dp[n][m],代表dna1要变为dna2所需要的最小操作次数
- 确定递推关系:
- 如果dna1[i-1] = dna2[j-1],则dp[i][j] = dp[i-1]j-1
- 如果不相等,那就有三种操作
- 插入:dp[i][j-1]+1,(相当于直接插入dna2的第j个字符)
- 删除:dp[i-1][j]+1,(相当于直接删除dna2的第j+1个字符)
- 替换:dp[i-1][j-1]+1,(相当于直接将dna1的第i个字符替换成dna2的第j个字符) 综上所述,最终dp[i][j]的值要取这三种操作的最小值
- 动态规划初始条件的确定
- dp[i][0] = i,表示将 word1 的前 i ii 个字符转换为空字符串的操作次数(全部删除)
- dp[0][j] = j,表示将空字符串转换为 word2 的前 j jj 个字符的操作次数(全部插入)
- 使用双重循环填充dp数组
- 最终返回结果应该是dp[m][n]
代码实现
public class Main {
public static int solution(String dna1, String dna2) {
// 编辑距离,动态规划
int n = dna1.length();
int m = dna2.length();
if(n ==0 || m == 0)
return Math.max(n, m);
//dp数组含义dp[i][j]表示dna1的前i个字符串变为dna2的前j个字符串需要几步
int[][] dp = new int[n+1][m+1];
//初始化
for(int i =0 ;i<=n;i++)
dp[i][0] = i;
for(int j = 0 ;j<=m;j++)
dp[0][j] = j;
for(int i = 1 ; i <= n ; i++){
for(int j = 1;j<=m;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][j-1], dp[i-1][j]))+1;
}
}
}
return dp[n][m];
}
public static void main(String[] args) {
// You can add more test cases here
System.out.println(solution("AGCTTAGC", "AGCTAGCT") == 2);
System.out.println(solution("AGCCGAGC", "GCTAGCT") == 4);
}
}