網上講最小編輯距離的文章有很多,但是看了一大堆,講明白的實在是很少。
最小編輯距離指的是字符串A轉化為字符串B的最小編輯次數,允許的操作有插入,刪除,替換。
先來說一下插入刪除操作,比如有hello,helo倆個字符串,前一個字符串減去一個l和后一個加上一個l,其實是沒有區別的。那么把這個操作統稱為對一個字符串的刪除就好了。
再來說一下替換操作,helo和halo,將e替換成a或者將a替換成e,其實都是沒區別的。
既然如此,那么大家都在說dp做最小編輯距離,那怎么理解呢。先上圖。
首先先說黑字部分。
首先一點是,如果雙方字符串為空,那么最小編輯距離為0。如果有任意一方字符串不為空,那么最小編輯距離就為len(str(not_None_string)),這也是沒問題的。
那么紅字部分怎么來的呢,dp的一個特性就是當前狀態由上一個狀態決定。那么假設我要判斷A[i:]和B[j:]的最小編輯距離,那么當前編輯距離是由上一個狀態的最小編輯距離決定,也就是說在上一個狀態需要修改最少多少次。上一個狀態是有這么幾種情況:
1.A[i-1:]與B[j]匹配需要修改K1次,如果此時加上了A[i],那么就不匹配了,需要把A[i]去掉,操作數K1+1
2.同理,A[i:]與B[j-1:]匹配需要修改K2次,如果此時加上了B[j],那么就不匹配了,需要把B[j]去掉,操作數K2+1
3.A[i-1:]與B[j-1:]匹配需要修改K3次,那么此時雙方各加上A[i],B[j],就要考慮了,如果倆個字符相同,那么操作數K3不變,如果字符不同,那么意味着要進行替換操作,不管誰替換誰都是K3+1
那么現在的狀態就是上面三種情況取(K1+1,K2+1,K3+(0?1))最小的那個,換成矩陣中的狀態轉移方程為:
dp[i,j] = min(dp[i-1,j]+1,dp[i,j-1]+1,dp[i-1,j-1]+(0:1?A[i]==B[j]))
為什么要從0開始,因為從空字符串開始會更好算一點,黑框這些值不由dp狀態生成,可以看成輔助計算的數組們。這個做法在很多需要二維矩陣的dp解法中都會運用到。多拿幾道題練幾遍就有思路了。
那么代碼如下:
def func(s1,s2): edit = [[i+j for j in range(len(s2)+1)] for i in range(len(s1)+1)] for i in range(1,len(s1)+1): for j in range(1,len(s2)+1): if s1[i-1]==s2[j-1]: d=0 else: d=1 edit[i][j] = min(edit[i-1][j]+1,edit[i][j-1]+1,edit[i-1][j-1]+d) return edit[-1][-1]
其實這種解體思路也可以用在求一些二維的最短路徑上,只不過生成的黑框不一樣,解法還是一樣的。