算法训练 Day 56

LeetCode 583. 两个字符串的删除操作

题目链接:583. 两个字符串的删除操作

思路:马上要做编辑距离这道经典题了,先练练手,使用动态规划五部曲分析。

  1. 确定dp数组及其下标的含义
    两个字符串,所以使用一个二维dp数组。
    dp[i][j]表示以 i-1 为结尾的字符串word1,和以 j-1 位结尾的字符串word2,两者要相等所需要删除元素的最少次数。
  2. 确定递归公式
    在遍历word1和word2的过程中,无非就是两种状况:word1[i-1]和word2[j-1]是否相等。如果相等的话就不需要进行元素的操作,所以 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] dp[i][j]=dp[i-1][j-1] dp[i][j]=dp[i1][j1]
    如果不相等的话,有三种状态可以选择,改word1,改word2,或者两者都改,选择这三者中的最小次数。所以递推公式为: d p [ i ] [ j ] = m i n ( d p [ i − 1 ] [ j ] + 1 , d p [ i ] [ j − 1 ] + 1 , d p [ i − 1 ] [ j − 1 ] + 2 ) dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]+2) dp[i][j]=min(dp[i1][j]+1,dp[i][j1]+1,dp[i1][j1]+2)
  3. dp数组初始化
    根据实际意义考虑二维dp数组的左边界和上边界,因为这两种情况,其中一个字符串都为空,所以另一个字符串要操作元素的次数就是字符串当前的长度,所以遍历的时候初始化即可。
  4. 确定遍历顺序为从前往后遍历
  5. 打印dp数组右下角的结果

go版本:

func minDistance(word1 string, word2 string) int {
    l1 := len(word1)
    l2 := len(word2)
    dp := make([][]int, l1+1)
	for i := 0; i <= l1; i++ {
		dp[i] = make([]int, l2+1)
        dp[i][0] = i
	}

	for j := 0; j <= l2; j++ {
		dp[0][j] = j
	}

	for i := 1; i <= l1; i++ {
		for j := 1; j <= l2; j++ {
			if word1[i-1] == word2[j-1] {
				dp[i][j] = dp[i-1][j-1]
			} else {
				dp[i][j] = min(min(dp[i-1][j]+1, dp[i][j-1]+1), dp[i-1][j-1]+2)
			}
		}
	}
	return dp[l1][l2]
}

func min(i, j int) int {
	if i < j {
		return i
	}
	return j
}

LeetCode 72. 编辑距离

题目链接:72. 编辑距离

思路:这道题与上一道题非常类似,我们细看一下差别在哪。上一题对字符串只能进行删除操作,但此题可以直接将一个元素修改成另一个元素,所以区别在于递推公式的部分。

在遍历word1和word2的过程中,无非还是两种状况:word1[i-1]和word2[j-1]是否相等。如果相等的话就不需要进行元素的操作,所以 d p [ i ] [ j ] = d p [ i − 1 ] [ j − 1 ] dp[i][j]=dp[i-1][j-1] dp[i][j]=dp[i1][j1]
如果不相等的话,也有三种状态可以选择,word1增加一个元素(相当于word2删除对应的元素),word1删除一个元素,或者word1修改其中的一个元素,选择这三者中的最小操作次数。所以递推公式为: d p [ i ] [ j ] = m i n ( d p [ i ] [ j − 1 ] + 1 , d p [ i − 1 ] [ j ] + 1 , d p [ i − 1 ] [ j − 1 ] + 1 ) dp[i][j] = min(dp[i][j-1]+1, dp[i-1][j]+1, dp[i-1][j-1]+1) dp[i][j]=min(dp[i][j1]+1,dp[i1][j]+1,dp[i1][j1]+1)。公式内部的三种变量分别对应上述的三种分析。

go版本:

func minDistance(word1 string, word2 string) int {
    l1 := len(word1)
    l2 := len(word2)
    dp := make([][]int, l1+1)
	for i := 0; i <= l1; i++ {
		dp[i] = make([]int, l2+1)
        dp[i][0] = i
	}

	for j := 0; j <= l2; j++ {
		dp[0][j] = j
	}

	for i := 1; i <= l1; i++ {
		for j := 1; j <= l2; j++ {
			if word1[i-1] == word2[j-1] {
				dp[i][j] = dp[i-1][j-1]
			} else {
				dp[i][j] = min(min(dp[i-1][j]+1, dp[i][j-1]+1), dp[i-1][j-1]+1)
			}
		}
	}
	return dp[l1][l2]
}

func min(i, j int) int {
	if i < j {
		return i
	}
	return j
}

你可能感兴趣的:(算法,leetcode,动态规划)