LeetCode学习笔记——编辑距离(动态规划)

个人博客:The Blog Of WaiterXiaoYY 欢迎来互相交流学习。

对动态规划的理解程度:★★◐☆☆

被动态规划折磨了这么久,今天总算是可以说有点手感了,

编辑距离也算是动态规划里面比较经典的,

当拿到题目的时候,也是很懵的,不愧是困难程度,

但如果按照动态规划的套路来分析问题,

或许能清晰一点,

动态规划的套路是什么?

分清状态选择


我们先来看一下题目:

给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数 。

你可以对一个单词进行如下三种操作:

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

给定两个单词,比如word1 = "horse",word2= "ros"

如果将 horse 转换成 ros ,怎么增/删/换的步骤是最少的,

我们知道这道题最少的步骤是 3,

具体是这样做的:

horse -> rorse (将 'h' 替换为 'r')
rorse -> rose (删除 'r')
rose -> ros (删除 'e')

那怎么样才能计算出最少的步骤?

穷举!

穷举什么?

对每一处都进行三次选择,

再取能令总的操作数最小的操作。

很抽象对不对。

做这个笔记时,曾一度中止,主要是在脑子里面无法形成生动形象的言语在字面上表现出来,

但如果理解了,现实中三言两语就可以说的清楚。

先看回我们这道题,

对比两个字符串,我们一般采用双指针,

上面操作的第一步是将 h 替换成 r,这其实是我们判断完后才知道的操作,

我们应该怎么判断?

我们需要两个指针,这两个指针分别指向两个字符串尾部,如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fnSwQBRK-1585277532790)(https://note.youdao.com/yws/api/personal/file/WEB4fa7acec03bcdcc3ad8c73316054da26?method=download&shareKey=bc2d9b8c1b77c48b935b02c1fa69217d)]

此时进行判断,

如果此处字符对应相等,那么不做任何操作,p,q都往前移动,操作数等于移动后对应的操作数

这里不理解?先暂时跳过加粗的部分,你现在只需要知道如果相同,就一起前移。

但实际上这里的两个字符是不同的,

那就得进行选择,到底是删掉e,还是将e替换成s,还是在后面补上s呢

小孩子才做选择,我全部都试一遍,

如果是删掉e,将变成这样:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0S8WSkkG-1585277532792)(https://note.youdao.com/yws/api/personal/file/WEBcf85b919a2dadbf69c28f13933f4b575?method=download&shareKey=a6b0f773ffd9c1e718e6ae496afd482a)]

p将迁移,q保持不动,

好,这是删掉的情况,如果是替换的情况呢?

替换之后就相等了,那么p,q都将往前迁移,如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-SntVmMDz-1585277532794)(https://note.youdao.com/yws/api/personal/file/WEB863cc4013d9cb170146083ac80bacc6b?method=download&shareKey=f13be864aad0190cef8d5902f5c0be23)]

如果是增加呢?

那就是在 e 的后面加上 s,然后p要保持不动,q所指已经有匹配了,所以 q 要向前移动,如图:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-MHAVTgt9-1585277532795)(https://note.youdao.com/yws/api/personal/file/WEB2f5ca93889601aac22889c940a9b44f5?method=download&shareKey=fd2cab6fe0fe93b389159aab51e2ed8e)]

好,到这里,以上每种操作,操作数都是 1,执行完之后,我们的操作数 + 1

咦?为什么是 1 不是 3 呢?

因为我们只需要上面的其中一种,虽然我们进行了三次操作,但是只有一种操作能使总的操作数最少,是谁呢?

暂时还不清楚,得看谁?

得看执行后的的位置上进行这样三次操作,一直到其中一个字符串被遍历完,

所以这就转换成为我们熟悉的 最优解子问题

要看我这个操作是不是能使总的操作数达到最小,就得看我的子问题能不能使操作数达到最小,

这就是我们的状态和选择,

回到我刚刚说的先不理会的加粗部分,如果此时两个字符相等,就一起迁移,

此时的问题就转成为子问题的求解,子问题最小,则其最小。

所以状态和选择我们都搞清楚了,只需要再搞清楚结束条件和初始值,就可以列举出我们的状态转移方程了。

  • 结束条件是什么?

当 p 或者 q指向字符串的前面时候,就代表结束了,以下展示的是同时到达最前面,也就是这个问题最优的情况,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-J4nAnlFI-1585277532796)(https://note.youdao.com/yws/api/personal/file/WEBa358f973a3ee71d5510013988f7ab9b9?method=download&shareKey=042293b40543e4d6a9b4007f2d96d9aa)]

如果是这样呢?

q走完了,但是p还没有走完,那就用删除操作把p前面的全部删掉,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AKxvDgGp-1585277532797)(https://note.youdao.com/yws/api/personal/file/WEBea58bedf61615afa668b8a3a8b9539fb?method=download&shareKey=b8b2c6425c0b5a16d79944b83cbc31e6)]

如果是 p 走完了,但是 q 没走完,那么就用增加操作将 q 前面的所有加到 p 所指的位置,

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ZzrjnVWM-1585277532798)(https://note.youdao.com/yws/api/personal/file/WEBb00f82efc2c78920860c25ff04138197?method=download&shareKey=b844226e8b197b82c1de2fc0e808af49)]

  • 那初始值是什么?

当然就是一方字符串为空,操作数就是另一字符串的长度。

到了这里,应该我们的状态转移方程就可以写出来了:

dp[i][j] = min(dp[i - 1][j - 1] + 1, dp[i - 1][j] + 1, dp[i][j - 1] + 1)
// i是指向word1的指针,j是指向word2的指针
//dp[i][j]表示当前位置的操作所能达到的最小操作数
//dp[i - 1][j - 1] + 1 表示替换,替换后的子问题加上1就是当前的最小操作数
//dp[i - 1][j] + 1 表示删除,删除后的子问题加1就是当前的最小操作数
//dp[i][j - 1] + 1 表示增加,增加后的子问题加1就是当前的最小操作数

代码
class Solution {
    public int minDistance(String word1, String word2) {
        //将字符串转为字符数组
        char []s1 = word1.toCharArray();
        char []s2 = word2.toCharArray();
        //创建一个二维数组
        int [][]dp = new int[s1.length + 1][s2.length + 1];
        //初始值条件
        for(int i = 1; i <= s1.length; i++)
            dp[i][0] = i;
        for(int j = 1; j <= s2.length; j++) 
            dp[0][j] = j;
        
        int temp;
        //开始遍历两个字符串
        for(int i = 1; i <= s1.length; i++) {
            for(int j = 1; j <= s2.length; j++) {
                //如果当前位置对应相等,则当前的最小操作数等于子问题的操作数
                if(s1[i - 1] == s2[j - 1])
                    dp[i][j] = dp[i - 1][j - 1];
                else {
                    //判断三种操作的最小操作数
                    temp = Math.min(dp[i - 1][j] + 1, dp[i][j - 1] + 1);
                    dp[i][j] = Math.min(dp[i - 1][j - 1] + 1, res);
                }
            }
        }
        return dp[s1.length][s2.length];
    }
}

呼~



整理于2020.3.26

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值