秒懂【编辑距离】!动态规划一步步拆解。

1.思路

当str1[i-1]==str[j-1] 时,不用编辑,因此dp[i-1][j-1]

当str1[i-1] != str[j-1] 时,需要编辑(删除、增加、或者修改选其中一个最小的值),因此dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1

alt

如果文字描述的不太清楚,你可以参考视频的详细讲解B站@好易学数据结构

2.代码

2.1 Python代码

#
# 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
#
#
# @param str1 string字符串
# @param str2 string字符串
# @return int整型
#
class Solution:
    def editDistance(self, str1: str, str2: str) -> int:
        # write code here
        m = len(str1)
        n = len(str2)
        # 1. 定义状态.   dp[i][j]:字符串str1[0:i - 1] 与str2[0:j - 1] 的最少操作数
        dp = [[0] * (n + 1) for _ in range(m + 1)]
        # 2. 初始化边界条件: dp[i][0] = i str1增加或删除i个元素会变成str2(str2为空); dp[0][j] = j str2增加或删除j个元素会变成str1(str1为空)
        # 2.1 初始化第0行
        for j in range(n + 1):
            dp[0][j] = j
        # 2.2 初始化边界第0列
        for i in range(m + 1):
            dp[i][0] = i
        # 3.确定递推公式:
        for i in range(1, m + 1):
            for j in range(1, n + 1):
                if str1[i - 1] == str2[j - 1]:
                    dp[i][j] = dp[i - 1][j - 1]  # 若是字符相同,此处不用编辑,直接等于前一个的距离
                else:
                    # 删、增、修改中获取最小再加上1(删、增、修改对应于1次编辑)
                    dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1
        # 4. 输出结果
        return dp[m][n]

2.2 Java代码

import java.util.*;


public class Solution {
    /**
     * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
     *
     *
     * @param str1 string字符串
     * @param str2 string字符串
     * @return int整型
     */
    public int editDistance (String str1, String str2) {
        // write code here
        int m = str1.length();
        int n = str2.length();
        // 1.定义状态.   dp[i][j]:字符串str1[0:i-1]与str2[0:j-1]的最少操作数
        int[][] dp = new int[m + 1][n + 1];
        // 2.初始化边界条件:dp[i][0] = i str1增加或删除i个元素会变成str2(str2为空); dp[0][j] = j str2增加或删除j个元素会变成str1(str1为空)
        // 2.1初始化第0行
        for (int j = 0; j <= n; j++) {
            dp[0][j] = j;
        }
        // 2.2初始化边界第0列
        for (int i = 0; i <= m; i++) {
            dp[i][0] = i;
        }
        // 3.确定递推公式:
        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                if (str1.charAt(i - 1) == str2.charAt(j - 1)) {
                    //若是字符相同,此处不用编辑,直接等于前一个的距离
                    dp[i][j] = dp[i - 1][j - 1];
                } else {
                    //删、增、修改中获取最小再加上1(删、增、修改对应于1次编辑)
                    dp[i][j] = min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1;
                }
            }
        }
        //4.输出结果
        return dp[m][n];
    }


    private int min(int a, int b, int c) {
        int res;
        if (a <= b && a <= c) {
            res = a;
        } else if (b <= a && b <= c) {
            res = b;
        } else {
            res = c;
        }
        return res;
    }
}

2.3 Go代码

package main


/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 *
 *
 * @param str1 string字符串
 * @param str2 string字符串
 * @return int整型
 */
func editDistance(str1 string, str2 string) int {
	// write code here
	m := len(str1)
	n := len(str2)
	// 1.定义状态.	   dp[i][j]:字符串str1[0:i-1]与str2[0:j-1]的最少操作数
	dp := newArray(m+1, n+1)
	// 2.初始化边界条件:dp[i][0] = i str1增加或删除i个元素会变成str2(str2为空); dp[0][j] = j str2增加或删除j个元素会变成str1(str1为空)
	// 2.1初始化第0行
	for j := 0; j <= n; j++ {
		dp[0][j] = j
	}
	// 2.2初始化边界第0列
	for i := 0; i <= m; i++ {
		dp[i][0] = i
	}
	// 3.确定递推公式:
	for i := 1; i <= m; i++ {
		for j := 1; j <= n; j++ {
			if str1[i-1] == str2[j-1] {
				dp[i][j] = dp[i-1][j-1] //若是字符相同,此处不用编辑,直接等于前一个的距离
			} else {
				//删、增、修改中获取最小再加上1(删、增、修改对应于1次编辑)
				dp[i][j] = min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1]) + 1
			}
		}
	}
	//4.输出结果
	return dp[m][n]
}

// 创建一个 m行n列的矩阵(二维数组)
func newArray(m int, n int) [][]int {
	arr := make([][]int, m)
	for i := 0; i < m; i++ {
		arr[i] = make([]int, n)
	}
	return arr
}
func min(a, b, c int) int {
	var res int
	if a <= b && a <= c {
		res = a
	} else if b <= a && b <= c {
		res = b
	} else {
		res = c
	}
	return res
}

如果上面的代码理解的不是很清楚,你可以参考视频的详细讲解B站@好易学数据结构