Leetcode 72. 编辑距离 动态规划 优化 C++实现

Leetcode 72.编辑距离

问题:给你两个单词 word1  word2, 请返回将 word1 转换成 word2 所使用的最少操作数  。

你可以对一个单词进行如下三种操作:插入一个字符,删除一个字符,替换一个字符。

算法1:递归搜索 + 保存计算结果 = 记忆化搜索

        创建 memo 数组,并赋初始值为 -1,表示还没有被计算过。

        进入 dfs 函数。引用 memo 数组,如果这个字母已经被计算过了就 return memo 的值。有四种情况,两个字母相等,这个位置就不用操作,向前继续递归;如果不相等,可以插入字母、删除字母、替换字母,取操作数最小的一个。

        例如在 word1 中插入字母,那么这个位置的问题就解决了,这个时候要让 word2 的指针前移,继续递归。如果在 word1 中删除字母,那么就要将 word1 的指针前移。如果替换字母,就让 word1 word2 的指针同时前移。

        dfs 中前两行代码表示的意思是,如果在递归过程中出现了 i 或者 j 小于 0 的情况,即 word1 或者 word2 已经遍历完了,那么另一个没有被遍历完的 word 剩余的字母个数就是 j + 1 或者 i + 1 ,这个时候直接 return j + 1 或者 i + 1 即可。

代码:

class Solution {
public:
    int minDistance(string word1, string word2) {
        int n = word1.length(), m = word2.length();
        vector<vector<int>> memo(n, vector<int>(m, -1)); // -1 表示还没有计算过
        auto dfs = [&](auto&& dfs, int i, int j) -> int {
            if (i < 0)    return j + 1;
            if (j < 0)    return i + 1;
            int& res = memo[i][j]; // 注意这里是引用
            if (res != -1)    return res; // 之前算过了
            if (word1[i] == word2[j])   return res = dfs(dfs, i - 1, j - 1);
            return res = min(min(dfs(dfs, i - 1, j), dfs(dfs, i, j - 1)), dfs(dfs, i - 1, j - 1)) + 1;
        };
        return dfs(dfs, n - 1, m - 1); // 递归入口
    }
};

算法2:1:1 翻译成递推

        创建二维数组 dp ,并赋初始值 0 。初始化第 0 行第 0 列,先赋最大值,即当前位置可能出现的最大值。

        开始循环递推,如果 word1 当前字母与 word2 当前字母相等,则 这个位置的操作数 dp 就等于 dp 前一个格子的值。

代码:

class Solution {
public:
    int minDistance(string word1, string word2) {
        int n = word1.length(), m = word2.length();
        vector<vector<int>> dp(n + 1,vector<int>(m + 1));
        for(int j = 0;j <= m;j++)   dp[0][j] = j; // 初始化第0行

        for(int i = 0; i < n; i++){
            dp[i + 1][0] = i + 1; // 初始化第0列
            for(int j = 0;j < m;j++)
                dp[i + 1][j + 1] = word1[i] == word2[j] ? dp[i][j] : min(min(dp[i][j],dp[i + 1][j]),dp[i][j + 1]) + 1;
        }
        return dp[n][m];
    }
};

算法3:空间优化:两个数组(滚动数组)

        通过 算法2 可知,行列表我们只会用到 2 行,每次递推只会取它的上一个格子的值,所以可以利用循环数组,来有效降低空间复杂度。

代码:

class Solution {
public:
    int minDistance(string word1, string word2) {
        int n = word1.length(),m = word2.length();
        vector<vector<int>> dp(2,vector<int>(m + 1));
        for(int j = 0;j <= m;j++)   dp[0][j] = j;
        for(int i = 0;i < n;i++){
            dp[(i + 1) % 2][0] = i + 1;
            for(int j = 0;j < m;j++)     
                dp[(i + 1) % 2][j + 1] = word1[i] == word2[j] ? dp[i % 2][j] : min(min(dp[i % 2][j],dp[(i + 1) % 2][j]),dp[i % 2][j + 1]) + 1;
        }
        return dp[n % 2][m];
    }
};

算法3:空间优化:一个数组

        创建一维数组 dp 并赋初始值。

        dp [ 0 ] 相当于原来的 dp [ 0 ] [ ] ,通过内层循环每循环一次就通过 dp [ 0 ] 自增来实现 + 1

        pre 相当于 dp [ i + 1 ] [ j ] ;

        没更新的 dp[ j + 1] 相当于 dp [ i ] [ j + 1] ;

        dp[ j ] 相当于 dp [ i ] [ j ];

        更新后的 dp[ j + 1] 相当于 dp [ i + 1] [ j + 1]

代码:

class Solution {
public:
    int minDistance(string word1, string word2) {
        int m = word2.length();
        vector<int> dp(m + 1);
        for(int j = 0;j <= m;j++)   dp[j] = j; // iota(dp.begin(), dp.end(), 0);

        for(char x : word1){
            int pre = dp[0];
            dp[0]++; // 对应二维数组方法时行数向下移,即 dp[i+1][0] = i+1
            for(int j = 0;j < m;j++){
                int temp = dp[j + 1];
                dp[j + 1] = x == word2[j] ? pre : min(min(dp[j + 1],dp[j]),pre) + 1;
                pre = temp;
            }
        }
        return dp[m];
    }
};

  • 11
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值