问题描述
解题思路
这是一道相当经典的编辑距离题目,考察的就是对动态规划思维的运用以及对dp数组的定义,按照动态规划的老套路来做,首先第一步就是:
明确dp数组含义:
因为我们需要求得的是最少的编辑步骤,那么我们将这个当成数组的数值,那么因为需要进行比较,所以我们要有两个维度的参数来支撑,因此定义的就是一个二维数组,那么我们就可以明确dp数组是什么了:dp[i][j]表示第一个字符串前i个位置和第二个字符串前j个位置的最小编辑距离。
明确递推公式
我们对两个字符串进行比较时候,如果第i个位置等于第j个位置(的字符)那么就dp[i][j] = dp[i - 1][j - 1],但是如果不相等,这时候就需要分类讨论了,但是由于增加,删除,替换都是只进行一步操作,所以如果第i和第j个位置不相等的话,无非就是判断i和j-1是否相等,j和i-1是否相等,如果不等就是直接替换,体现到代码上面就比较简单,只需要判断大小,dp[i][j] = Math.min(dp[i - 1][j] + 1, Math.min(dp[i][j - 1] + 1, dp[i-1][j-1] + 1));
初始化
初始化是我们递推公式开始的第一步,一定要仔仔细细的查看,本题呢对dp数组进行理解,不难发现当有一个下标为零的时候,变换成它最少需要另外一个下标的数值(删除),由此我们就可以开始初始化。
遍历方向
遍历方向不是本题的难点,由递推公式就可以看出来,dp[i][j]依赖于前面的状态,所以遍历方向就是从前往后遍历。
public static int solution(String dna1, String dna2) {
// Please write your code here
int m = dna1.length();
int n = dna2.length();
int[][] dp = new int[m + 1][n + 1];
// 初始化 dp 数组
for (int i = 0; i <= m; i++) {
dp[i][0] = i;
}
for (int j = 0; j <= n; j++) {
dp[0][j] = j;
}
//dp数组的含义是第i个字符前(从零开始的)的编辑距离
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][j - 1] + 1, dp[i-1][j-1] + 1));
}
}
}
return dp[m][n];
}
总结
本题真的是相当经典编辑距离类题目,其代码值得好好琢磨,笔者认为,这里最主要的难点就是去判断这个递推公式,这是比较难想到的地方,但是如果你一下子就想到了这个逻辑判断,那么应该就会很快解决。