coverPiccoverPic

Leetcode 72 Edit Distance 编辑距离怎么做

思路

一直都不知道类似计算两个字符串的“距离”的题目怎么写,于是就有了这篇文章,先看一个经典的编辑距离

题目给出两个字符串,并且可以对它们进行增加、修改、插入一个字符的操作,求最少的使两个字符串相等的操作步数ss

从后往前看,假设两个字符串是word1 = 'abcd'word2 = 'abcc',当前下标分别是iijj,每一步遍历都有 4 个可能的分支:

  1. 末尾字符不相等,word1[i] != word2[j]
    1.1. 可以把word1[i]替换为word2[j],然后iijj各前移一位,操作步数ss + 1;
    1.2. 删掉word1[i],然后ii前移一位,操作步数ss + 1。其实这和从头到尾遍历到i1i-1jj时,word1增加一个word2[j]一样;
    1.3. 删掉word2[j],然后jj前移一位,操作步数ss + 1;
  2. 末尾字符相等,则iijj各前移一位,,操作步数ss不变。

记忆化搜索

于是就有了递归式的代码,这里方便起见把空字符''记为单词第一个元素。

此外,这里加上记忆化搜索,因为暴力递归的话,会使得代码时间复杂度达到O(2mn)O(2^{mn})mmnn是字符串长度,记忆化搜索时间、空间复杂度都为O(mn)O(mn)

ts
  1. function minDistance(word1: string, word2: string): number {
  2. let len1 = word1.length
  3. let len2 = word2.length
  4. if (len1 ===0 || len2 === 0) {
  5. return len1 + len2
  6. }
  7. const cache = []
  8. for (let i = 0; i <= len1; i++) {
  9. cache[i] = new Array(len2 + 1).fill(-1)
  10. }
  11. const dfs = (i: number, j: number): number => {
  12. if (cache[i][j] >= 0) {
  13. return cache[i][j]
  14. }
  15. let ans
  16. if (i === 0 || j === 0) {
  17. ans = i || j
  18. } else if (word1[i - 1] !== word2[j - 1]) {
  19. ans = Math.min(
  20. dfs(i - 1, j),
  21. dfs(i, j - 1),
  22. dfs(i - 1, j - 1)
  23. ) + 1
  24. } else {
  25. ans = dfs(i - 1, j - 1)
  26. }
  27. return cache[i][j] = ans
  28. }
  29. return dfs(len1, len2)
  30. }

递推式动态规划

类似的,我们可以使用递推式,从上面的思路可知,递推式的初始状态是,下标都指向单词的第一项空字符时,此时这个字符相等,只需要操作需要 0 步。当其中一个下标指向空字符,当前操作步数为abs(ij)\text{abs}(i-j)

另外,这里进行了状态压缩,用两行的数组代替了所需的m×nm \times n的数组,时间复杂度O(mn)O(mn),空间复杂度O(min(m,n))O(\min(m,n))

ts
  1. function minDistance(word1: string, word2: string): number {
  2. let len1 = word1.length
  3. let len2 = word2.length
  4. if (len1 === 0 || len2 === 0){
  5. return len1 + len2
  6. }
  7. if (len1 < len2) {
  8. return minDistance(word2, word1)
  9. }
  10. const dp: [number[], number[]] =[[], []]
  11. for (let j = 0; j < len2 + 1; j++) {
  12. dp[0][j] = j;
  13. }
  14. for (let i = 1; i < len1 + 1; i++) {
  15. for (let j = 0; j < len2 + 1; j++) {
  16. dp[1][j] = j === 0
  17. ? i
  18. : word1[i - 1] !== word2[j - 1]
  19. ? Math.min(
  20. dp[0][j - 1],
  21. dp[0][j],
  22. dp[1][j - 1]
  23. ) + 1
  24. : dp[0][j - 1]
  25. }
  26. [dp[0], dp[1]] = [dp[1], dp[0]]
  27. }
  28. return dp[0][len2]
  29. }
0 条评论未登录用户
Ctrl or + Enter 评论
© 2023-2025 LittleRangiferTarandus, All rights reserved.
🌸 Run