LeetCode 583. 两个字符串的删除操作
题目链接:583. 两个字符串的删除操作
思路:马上要做编辑距离这道经典题了,先练练手,使用动态规划五部曲分析。
- 确定dp数组及其下标的含义
两个字符串,所以使用一个二维dp数组。
dp[i][j]表示以 i-1 为结尾的字符串word1,和以 j-1 位结尾的字符串word2,两者要相等所需要删除元素的最少次数。 - 确定递归公式
在遍历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[i−1][j−1]。
如果不相等的话,有三种状态可以选择,改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[i−1][j]+1,dp[i][j−1]+1,dp[i−1][j−1]+2)。 - dp数组初始化
根据实际意义考虑二维dp数组的左边界和上边界,因为这两种情况,其中一个字符串都为空,所以另一个字符串要操作元素的次数就是字符串当前的长度,所以遍历的时候初始化即可。 - 确定遍历顺序为从前往后遍历
- 打印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[i−1][j−1]。
如果不相等的话,也有三种状态可以选择,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][j−1]+1,dp[i−1][j]+1,dp[i−1][j−1]+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
}