[leetcode] 72.Edit Distance 编辑距离-史前最简明清晰的解答

题目:

给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。

你可以对一个单词进行如下三种操作:

  1. 插入一个字符
  2. 删除一个字符
  3. 替换一个字符
输入: word1 = "horse", word2 = "ros"
输出: 3
解释: 
horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')

输入: word1 = "intention", word2 = "execution"
输出: 5
解释: 
intention -> inention (删除 't')
inention -> enention (将 'i' 替换为 'e')
enention -> exention (将 'n' 替换为 'x')
exention -> exection (将 'n' 替换为 'c')
exection -> execution (插入 'u')


分析:

本题目符合动态规划思想:原问题可以拆分成重叠的子问题进行解决,我们使用动态规划四步法:

1、刻画一个最优解的结构特征

2、递归定义最优解的值

3、计算最优解的值,通常采用自底向上的方法

4、利用计算出的信息构造一个最优解

(引自算法导论)

步骤一:刻画编辑距离的特征

    horse -> ros 可由 [horse->rose子问题]->ros 组成,而[horse->rose子问题] 又可由它的子问题[horse->rorse子问题]->rose 组成,于是可构造递推公式 Mn=Mn-1+min(.),也就是说本次变换只跟 [上次已完成的变换] 和 [本次操作] 有关。

步骤二:分析递归解

    word1每个字符的下标使用i表示 word2 每个字符下标使用j表示,我们将word1对应word2的字符的每次变换使用二维数组e[][]表示,其中:

    e[i][j] = word1[i]转换到word2[j]的最小操作次数

那么操作方式有三种insert插入、delete删除、replace替换,我们只需选择其中最小的操作次数记录下来,即:

    e[i][j] = min(insert,delete,replace)

下面分析完整递归解:

e[i][j] = 
        i ; (当j=0时_①)
        j ; (当i=0时_②)
        e[i - 1][j - 1] ;(当word1[i]=word2[j]时_③) 
        min (  e[i][j - 1] + 1 ,  e[i - 1][j] + 1 ,  e[i - 1][j - 1] + 1  ); (当word1[i]!=word2[j]_④)

	注:
	    ①当j=0时,即由word1的任何字符变换到空时为删除,word1[i]->null,删除次数就是word1的索引 i ;
	    ②当i=0时,即由空变换到word2的任何字符时为插入,null->word2[j],插入次数就是word2的索引 j ; 
	    ③当word1[i]=word2[j]时,不做插入,延续上次操作次数;
	    ④当word1[i]!=word2[j]时:
		    其中第一项insert:从word1[i]->word2[j]的插入操作只需在word2上一次操作基础上增加一次,word1不变;
		    其中第二项delete:从word1[i]->word2[j]的删除操作只需在word1上一次操作基础上增加一次,word2不变;
		    其中第三项replace:从word1[i]->word2[j]的修改操作意味着,在两个字符串上一次操作基础之上做一次插入。


步骤三、四:计算编辑距离、返回最终解java代码
	public int minDistance(String word1, String word2) {
		int[][] e = new int[word1.length() + 1][word2.length() + 1];
		for (int i = 1; i <= word1.length(); i++)
			e[i][0] = i;
		for (int j = 1; j <= word2.length(); j++)
			e[0][j] = j;
		for (int i = 1; i <= word1.length(); i++) {
			for (int j = 1; j <= word2.length(); j++) {
				// 因为变换是从空字符串开始的而不是从word1[0]和word2[0]处开始的,所以i,j变换的实际是i-1,j-1处的字符,所以charAt索引要减一
				if (word1.charAt(i - 1) == word2.charAt(j - 1))
					e[i][j] = e[i - 1][j - 1];
				else
					e[i][j] = Math.min(e[i][j - 1], Math.min(e[i - 1][j], e[i - 1][j - 1])) + 1;
			}
		}
		return e[word1.length()][word2.length()];
	}

你可能感兴趣的:([leetcode] 72.Edit Distance 编辑距离-史前最简明清晰的解答)