算法—leetcode—72. 编辑距离

166 阅读2分钟

题目

  1. 编辑距离

题目描述

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

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

插入一个字符 删除一个字符 替换一个字符

示例

示例一

输入: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、明确base case
当一个字符串已经全部扫描完的情况,则直接累加另一个字符串剩余的长度
2、状态转移
两个字符串相等情况,则直接跳过
否则求插入/删除/替换中最小的方式
3、使用备忘录解决重复子问题

代码

package leetcode

import (
    "log"
    "fmt"
)

// minDistance
// 72. 编辑距离
// 使用递归方式解决动态规划问题
func minDistance(word1 string, word2 string) int {
    // 备忘录
    memorandum := map[string]int{}
    
	var dp func(i, j int) int
	dp = func(i, j int) (rs int) {
		// TODO 验证
		defer func() {
			// log.Println(i, j, rs)
		}()
        
        // 备忘录解决重叠子问题
        key := fmt.Sprintf("%d%d", i, j)
        if data, ok := memorandum[key]; ok {
            log.Println(key)
            return data
        }
        
		// base case
		// 当一个字符串已经全部扫描完的情况,则直接累加另一个字符串剩余的长度
		if i == -1 {
			rs = j + 1
			return
		}
		if j == -1 {
			rs = i + 1
			return
		}

		// 状态转移
		// 两个字符串相等情况,则直接跳过
		if word1[i] == word2[j] {
			rs = dp(i-1, j-1)
            memorandum[key] = rs
			return
		}
		// 插入/删除/替换
		rs = min((dp(i, j-1) + 1), (dp(i-1, j) + 1), (dp(i-1, j-1) + 1))
        memorandum[key] = rs
		return
	}

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

// min
// 求最小值
func min(a, b, c int) int {
	minNums := a
	if b < minNums {
		minNums = b
	}
	if c < minNums {
		minNums = c
	}
	return minNums
}

// minDistanceV
// 编辑距离
// 使用DP table
func minDistanceV(word1 string, word2 string) int {
    m := len(word1)
    n := len(word2)
    // 创建DP数组存储切片
    dp := createSlice(m+1, n+1)
    
    // base case
    for i := 1; i <= m; i++ {
        dp[i][0] = i
    }
    
    for i := 1; i <= n; i++ {
        dp[0][i] = i
    }
    
    // 自底向上求解
    for i := 1 ;i <=m; i++ {
        for j := 1; j <= n; j ++ {
            if word1[i-1] == word2[j-1] {
                dp[i][j] = dp[i-1][j-1]
            }else{
                dp[i][j] = min(dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+1)
            }
        }
    }
    log.Println(dp)
    return dp[m][n]
}

// createSlice
// 创建二维切片
func createSlice(m, n int) [][]int{
    data := make([][]int, m)
    for key:= range data{
        data[key] = make([]int, n)
    }
    return data
    
}

参考

来源:力扣(LeetCode)
链接:leetcode-cn.com/problems/ed…
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。