0072. Edit Distance

题目

Given two strings word1 and word2, return the minimum number of operations required to convert word1 to word2.

You have the following three operations permitted on a word:

  • Insert a character
  • Delete a character
  • Replace a character

Example 1:

Input: word1 = "horse", word2 = "ros"
Output: 3
Explanation: 
horse -> rorse (replace 'h' with 'r')
rorse -> rose (remove 'r')
rose -> ros (remove 'e')

Example 2:

Input: word1 = "intention", word2 = "execution"
Output: 5
Explanation: 
intention -> inention (remove 't')
inention -> enention (replace 'i' with 'e')
enention -> exention (replace 'n' with 'x')
exention -> exection (replace 'n' with 'c')
exection -> execution (insert 'u')

Constraints:

  • 0 <= word1.length, word2.length <= 500
  • word1 and word2 consist of lowercase English letters.

題目大意

可以對一個字符串進行三種操作, 插入, 刪除, 替換 現在給你兩個字符串word1,word2, 計算出word1轉換成word2最少需要多少次操作

解題思路

https://mp.weixin.qq.com/s/ShoZRjM8OyvDbZwoXh6ygg 解決兩個字符串的動態規劃問題, 一班都是用兩個指針 i, j 分別指向兩個字符串的最後, 然後一步步往前走, 縮小問題的規模

if word1[i] == word2[j]:
    skip
    i,j同時往前
else:
    # insert
    # delete
    # replace
dp = [
    [0,1,2,3,4,5],
    [1,1,2,2,3,4],
    [2,2,1,2,3,4],
    [3,3,2,2,2,3]
]
word1 \ word2 "" h o r s e
"" 0 1 2 3 4 5
r 1 1 2 2 3 4
o 2 2 1 2 3 4
s 3 3 2 2 2 3

dp(i,j) 返回值, 就是 word1[0..i] 和 word2[0..j]的最小編輯距離 dp(1,0) "ro" , "h" 最小編輯距離 2

dp[i-1][j-1] dp[i-1][j]
dp[i][j-1] dp[i][j]
替換/跳過 刪除
插入

來源

解答

https://github.com/kimi0230/LeetcodeGolang/blob/master/Leetcode/0072.Edit-Distance/main.go

package editdistance

import "fmt"

// 遞迴 (暴力解)
func MinDistance(word1 string, word2 string) int {
    var dp func(int, int) int
    dp = func(i, j int) int {
        // base case
        if i == -1 {
            return j + 1
        }
        if j == -1 {
            return i + 1
        }
        if word1[i] == word2[j] {
            // word1[0..i] 和 word2[0..j]的最小編輯距離等於 word1[0..i-1] 和 word2[0..j-1]
            // 本來就相等所以不需要任何操作
            // 也就是說 dp(i,j)等於 dp(i-1,j-1)
            return dp(i-1, j-1)
        } else {
            return min(
                dp(i, j-1)+1,   // insert: 直接在 word1[i]中插入一個和word2[j]一樣的字符, 那麼word2[j]就被匹配了,往前j, 繼續和i對比, 操作次數+1
                dp(i-1, j)+1,   // delete: 直接把 word1[i] 這個字符串刪除, 往前 i 繼續和 j 對比, 操作次數+1
                dp(i-1, j-1)+1, // replace: 直接把 word1[i] 替換成 word2[j], 這樣他們就匹配了, 同時往前 i, j 繼續對比, 操作次數+1
            )
        }
    }

    return dp(len(word1)-1, len(word2)-1)
}

// Memo優化
func MinDistanceMemo(word1 string, word2 string) int {
    var dp func(int, int) int
    memo := map[string]int{}
    dp = func(i, j int) int {
        key := fmt.Sprintf("%d,%d", i, j)
        // 查詢備忘錄 避免重複
        if _, ok := memo[key]; ok == true {
            return memo[key]
        }

        // base case
        if i == -1 {
            return j + 1
        }
        if j == -1 {
            return i + 1
        }
        if word1[i] == word2[j] {
            // word1[0..i] 和 word2[0..j]的最小編輯距離等於 word1[0..i-1] 和 word2[0..j-1]
            // 本來就相等所以不需要任何操作
            // 也就是說 dp(i,j)等於 dp(i-1,j-1)
            memo[key] = dp(i-1, j-1)
        } else {
            memo[key] = min(
                dp(i, j-1)+1,   // insert: 直接在 word1[i]中插入一個和word2[j]一樣的字符, 那麼word2[j]就被匹配了,往前j, 繼續和i對比, 操作次數+1
                dp(i-1, j)+1,   // delete: 直接把 word1[i] 這個字符串刪除, 往前 i 繼續和 j 對比, 操作次數+1
                dp(i-1, j-1)+1, // replace: 直接把 word1[i] 替換成 word2[j], 這樣他們就匹配了, 同時往前 i, j 繼續對比, 操作次數+1
            )
        }
        return memo[key]
    }

    return dp(len(word1)-1, len(word2)-1)
}

// DP table 優化, DP table 是自底向上求解, 遞迴是自頂向下求解
func MinDistanceDP(word1 string, word2 string) int {
    m, n := len(word1), len(word2)
    // 初始化  dp table : [][]int{}
    dp := make([][]int, m+1)
    for i := 0; i < m+1; i++ {
        dp[i] = make([]int, n+1)
    }

    // base case
    for i := 1; i <= m;="" i++="" {="" dp[i][0]="i" }="" for="" j="" :="1;" <="n;" j++="" dp[0][j]="j" 向上求解="" i="" if="" word1[i-1]="=" word2[j-1]="" dp[i][j]="dp[i-1][j-1]" else="" dp[i][j-1]+1,="" insert="" dp[i-1][j]+1,="" delete="" dp[i-1][j-1]+1,="" replace="" )="" return="" dp[m][n]="" type="" number="" interface="" int="" |="" int64="" float64="" func="" min[t="" number](vars="" ...t)="" t="" min="" _,="" vars=""> i {
            min = i
        }
    }

    return min
}
go test -benchmem -run=none LeetcodeGolang/Leetcode/0072.Edit-Distance -bench=.
goos: darwin
goarch: amd64
pkg: LeetcodeGolang/Leetcode/0072.Edit-Distance
cpu: Intel(R) Core(TM) i5-8259U CPU @ 2.30GHz
BenchmarkMinDistance-8            398260              3748 ns/op               0 B/op          0 allocs/op
BenchmarkMinDistanceMemo-8        102272             10796 ns/op            2211 B/op         69 allocs/op
BenchmarkMinDistanceDP-8         1944886               794.2 ns/op           688 B/op          9 allocs/op
PASS
ok      LeetcodeGolang/Leetcode/0072.Edit-Distance      5.717s
© Kimi Tsai all right reserved.            Updated : 2024-05-06 09:36:37

results matching ""

    No results matching ""