原文发表于:
编辑距离,可以用于度量两个字符串的差异。其含义是:一个字符串到另一个字符串的最少变换次数,其中,变换操作仅涉及增删改,且每次只能操作一个字符。
编辑距离的应用很广,比如纠错检错:
编辑距离,在笔试面试中会经常涉及到。一朋友最近参加了T公司的面试,便遇到了编辑距离:
编辑距离,是一个典型的动态规划问题。那么,从一个字符串到另一个字符串的编辑距离一定存在吗?这是必然的,暴力方法可以证明,不必赘述。
记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], 则可以进行三种操作(增删改),如下:
a. 把A的前i-1个字符变成B的前j个字符,然后删除一个字符;
b. 把A的前i个字符变成B的前j-1个字符,然后增加一个字符;
c. 把A的前i-1个字符变成B的前j-1个字符,然后改变一个字符;
显然,此时的动态规划方程为:
dp[i][j] = 1 + min{dp[i-1][j],dp[i][j-1],dp[i-1][j-1]}
算法搞懂后,程序就简单了:
func minDistance(A string, B string) int {
lenA := len(A)
lenB := len(B)
// 初始化二维slice
dp := make([][]int, lenA + 1)
for i := 0; i < lenA + 1; i++ {
dp[i] = make([]int, lenB + 1)
}
for i := 0; i < lenA + 1; i++ {
dp[i][0] = i
}
for j := 0; j < lenB + 1; j++ {
dp[0][j] = j
}
for i := 1; i < lenA + 1; i++ {
for j := 1; j < lenB + 1; j++ {
if A[i - 1] == B[j - 1] {
dp[i][j] = dp[i-1][j-1]
}else {
dp[i][j] = 1 + min(dp[i-1][j], dp[i][j-1], dp[i-1][j-1])
}
}
}
return dp[lenA][lenB]
}
func min(x, y, z int) int {
m := x
if x > y {
m = y
}
if m > z {
m = z
}
return m
}
在leetcode上测试,通过。
周末愉快,祝应届毕业生和社招的朋友拿到更好的offer.