Leetcode 72. Edit Distance
Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.)
You have the following 3 operations permitted on a word:
a) Insert a character
b) Delete a character
c) Replace a character
【思路分析】
编辑距离是一道很经典的动态规划的算法题目。
编辑距离,又称Levenshtein距离(莱文斯坦距离也叫做Edit Distance),是指两个字串之间,由一个转成另一个所需的最少编辑操作次数,如果它们的距离越大,说明它们越是不同。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。
这个概念是由俄罗斯科学家Vladimir Levenshtein在1965年提出来的,所以也叫 Levenshtein 距离。它可以用来做DNA分析,拼字检测,抄袭识别等等。总是比较相似的,或多或少我们可以考虑编辑距离。
在概念中,我们可以看出一些重点那就是,编辑操作只有三种。插入,删除,替换这三种操作,我们有两个字符串,将其中一个字符串经过上面的这三种操作之后,得到两个完全相同的字符串付出的代价是什么就是我们要讨论和计算的。
例如:
我们有两个字符串: kitten 和 sitting:
现在我们要将kitten转换成sitting
我们可以做如下的一些操作:
kitten -> sitten 将k替换成s
sitten -> sittin 将 e 替换成i
sittin -> sitting 添加g
在这里我们设置每经过一次编辑,也就是变化(插入,删除,替换)我们花费的代价都是1。
例如:
如果str1=”ivan”,str2=”ivan”,那么经过计算后等于 0。没有经过转换。
如果str1=”ivan1”,str2=”ivan2”,那么经过计算后等于1。str1的”1”转换”2”,转换了一个字符,所以距离是1。
这是一个典型的动态规划的问题。一个字符串到另一个字符串的编辑距离是必然存在的。
记dp[i][j]为字符串A的前i个字符到字符串B前j个字符的编辑距离,如果A或B为空串,那么i或j为0,因此i的区间为[0, lenA],j的区间为[0, lenB]。
接下来,我们推导动态规划的转移方程。
1. 如果A[i]等于B[j],那么此时有 dp[i][j] = dp[i-1][j-1]
2. 如果A[i]不等于B[j],则可以进行3种操作(增删改),如下:
a. 把A的前i-1个字符变为B的前j个字符,然后删除一个字符
b. 把A的前i个字符变为B的前j-1个字符,然后增加一个字符
c. 把A的前i-1个字符变为B的前j-1个字符,然后修改一个字符
此时动态规划的转移方程如下:
dp[i][j] = min{dp[i-1][j], dp[i-1][j-1], dp[i][j-1]} + 1
【java代码】
1 class Solution { 2 public int minDistance(String word1, String word2) { 3 int len1 = word1.length(); 4 int len2 = word2.length(); 5 6 if(len1 == 0) return len2; 7 if(len2 == 0) return len1; 8 9 int[] dp = new int[len1+1]; 10 11 for(int j = 0; j <= len1; j++) { 12 dp[j] = j; 13 } 14 15 for(int i = 1; i <= len2; i++) { 16 int pre = dp[0]; 17 dp[0] = i; 18 19 for(int j = 1; j <= len1; j++) { 20 int temp = dp[j]; 21 int k = 0; 22 if(word1.charAt(j-1) != word2.charAt(i-1)) k = 1; 23 dp[j] = Math.min(Math.min(dp[j-1], dp[j]) + 1, pre+k); 24 pre = temp; 25 } 26 } 27 28 return dp[len1]; 29 } 30 }