【dp】LeetCode 72:编辑距离

发布于:2024-11-27 ⋅ 阅读:(72) ⋅ 点赞:(0)

72. 编辑距离 - 力扣(LeetCode)

06e3e8f4d888495e9482cca94d45f401.png

动态规划思考路径:

1、根据题目所给的条件和目标,构造问题

2、拆解子问题,即定义状态

3、求解简单子问题,判断是否有可以直接求解的子问题。通常是dp数组的初始化

4、通过已知问题求解,即构造状态转移方程

5、判断复杂度是否在千万级别内,如果超过则超时

一、构造问题

 根据题意,本题的目标为:给你两个单词 word1 和 word2,将word1转换为word2,并求出转换所需的最小次数。

二、将所给条件缩小,拆解为子问题

我们以示例一为例:

题目要求我们将字符串“horse”转换为“ros”,乍一看或许没什么思路。我们定义lena和lenb分别为两个字符串的长度,那么求解Question(lena - 1, lenb - 1),Question(lena , lenb - 1),Question(lena - 1, lenb)就是缩小条件后的子问题,Question(0, 0)就是最小的子问题。

动态规划的核心思想就在于当前问题可以由子问题的状态推导而来。

我们进而将所有的问题列举出来,形成一个二维矩阵:

        a9dab07af1344ae68166972b35e9ca00.png

那么dp[i][j]所表示的就是word1前i个字符转换为word2前j个字符所需要的最少的操作次数。

三、求解简单子问题,判断是否有可以直接求解的子问题。通常是dp数组的初始化

通过观察,当word1为空时,word1所转换为word2的字串所需要的最小的操作次数即为word2字串的长度。所以我们如此初始化:

        1a5482fe00b54acf844e06efb197a6a2.png

  1. 初始化

    • dp[i][0] = i:将 word1 的前 i 个字符转换为空字符串 word2[0],需要 i 次删除操作。
    • dp[0][j] = j:将空字符串 word1[0] 转换为 word2 的前 j 个字符,需要 j 次插入操作。

 

四、通过已知问题求解,即构造状态转移方程

 ​​​​题目要求我们可以对一个单词进行如下三种操作:

  • 插入一个字符
  • 删除一个字符
  • 替换一个字符

对于word1: 

1、如果 word1[i] == word2[j],则 dp[i][j] = dp[i-1][j-1],即当前字符相等,直接从前一个状态dp[i-1][j-1]的转化来,不需要任何额外操作。

 af6e3453710644f9ae930b182b346980.png

2、如果 word1[i] != word2[j],则 dp[i][j] 可以从以下三种操作中选择最小值

4b11f4970018466790543de62212054a.png

  • 如果选择插入操作,即从状态dp[i][j-1]转化到dp[i][j],此时dp[i][j] = dp[i][j-1] + 1。
  • 如果选择删除操作,即从状态dp[i-1][j]转化到dp[i][j],此时dp[i][j] = dp[i-1][j] + 1。
  • 如果选择替换操作,此时无需关心word1[i]和word2[j],相当于word1和word2各删除一个字符,即从状态dp[i-1][j-1]转化到dp[i][j],此时dp[i][j] = dp[i-1][j-1] + 1。

注: 对于word1

  • dp[i-1][j-1] + 1:替换字符 word1[i] 为 word2[j]
  • dp[i-1][j] + 1:删除字符 word1[i]
  • dp[i][j-1] + 1:插入字符 word2[j] 到 word1。(也相当于word2字符串删除word2[j],但本题的分析是基于word1字符串的。)

完整代码:

【小技巧】:在动态规划问题中,为 dp 数组多设置一行一列可以简化边界条件的处理,避免了在状态转移时对边界情况的特殊处理。通过在字符串开头增加一个字符(通常是空字符),可以使 dp 数组的下标与字符串的下标一一对应,从而简化代码逻辑。

class Solution {
public:
    int minDistance(string word1, string word2) {
        // 首先拆解子问题:
        // word1前i个字符 如何转换成 word2前i个字符,所使用的最少操作次数

        // 四种状态
        // 1、什么也不做,word1 == word2
        // 2、第i步为插入一个字符后,转换成word2的最少操作数
        // 3、第i步为删除一个字符后。。。
        // 4、第i步为替换一个字符后。。。
        string str1 = " " + word1;
        string str2 = " " + word2;
        int len1 = str1.size(), len2 = str2.size();
        vector<vector<int>> dp(len1, vector<int>(len2, 0));
        for(int i = 0; i < len1; i++)
        {
            for(int j = 0; j < len2; j++)
            {
                if(i == 0){
                    dp[i][j] = j;
                }else if(j == 0){
                    dp[i][j] = i;
                }else if(str1[i] == str2[j]){
                    dp[i][j] = dp[i - 1][j - 1];
                }else{
                    dp[i][j] = min(dp[i - 1][j - 1]/*替换*/, min(dp[i - 1][j]/*删除*/, dp[i][j - 1]/*插入*/)) + 1;
                }
            }
        }
        return dp[len1 - 1][len2 - 1];
    }
};

 

 


网站公告

今日签到

点亮在社区的每一天
去签到