72. 编辑距离

  1. 题目链接

  2. 解题思路

    • 直接暴力递归,process(i, j)word1[i...]转换成word2[j...]需要的最少操作次数,也就是说,i字符之前的不用处理了,已经变成了j字符之前的了。
    • 如果word1[i] == word2[j]
      • 可以什么操作都不干,i和j就完成了,所以返回process(i + 1, j + 1)
      • 也可以插入一个字符word2[j],所以返回process(i, j + 1) + 1,注意这里操作了一次要加1.
      • 也可以删除一个字符,所以返回process(i + 1, j) + 1
    • 如果word1[i] != word2[j]
      • 可以替换成word2[j],所以返回process(i + 1, j + 1) + 1
      • 可以插入一个字符word2[j],所以返回process(i, j + 1) + 1
      • 可以删除一个字符,所以返回process(i + 1, j) + 1
    • 为了写代码好看,可以在相等的时候,也加一个「替换字符」的操作(虽然替换字符的操作肯定是不会是最优解)。
    • 递归函数,两个可变参数,所以直接加缓存就行,这就是「自顶向下」的动态规划。
  3. 代码

    class Solution {
    public:
    
        int process(const string& s1, const string &s2, int i, int j, vector<vector<int>> &dp) {
            if (i == s1.size() && j == s2.size()) {    // 都到结尾了  不需要操作了  返回0
                return 0;
            }
            if (i == s1.size()) {    //  只能在后面加字符了
                return s2.size() - j;
            }
            if (j == s2.size()) {     // 只能把后面的字符删除了
                return s1.size() - i;
            }
            if (dp[i][j] != -1) {
                return dp[i][j];
            }
            // 删除操作
            int del_res = process(s1, s2, i + 1, j, dp) + 1;
            // 插入操作
            int insert_res = process(s1, s2, i, j + 1, dp) + 1;
            // 替换操作
            int replace_res = process(s1, s2, i + 1, j + 1, dp) + 1;
            int do_nothing = INT32_MAX;    // 这种情况不一定有  相等的时候才有
            if (s1[i] == s2[j]) {
                do_nothing = process(s1, s2, i + 1, j + 1, dp);
            }
            dp[i][j] =  min(del_res, min(insert_res, min(replace_res, do_nothing)));
            return dp[i][j];
    
        }
    
        int minDistance(string word1, string word2) {
            int n = word1.size();
            int m = word2.size();
            vector<vector<int>> dp(n, vector<int>(m, -1));
            return process(word1, word2, 0, 0, dp);
        }
    };
    
posted @ 2024-11-11 09:26  ouyangxx  阅读(19)  评论(0)    收藏  举报