• [leetcode] 72. 编辑距离(二维动态规划)


    72. 编辑距离


    再次验证leetcode的评判机有问题啊!同样的代码,第一次提交超时,第二次提交就通过了!

    此题用动态规划解决。

    这题一开始还真难到我了,琢磨半天没有思路。于是乎去了网上喵了下题解看到了动态规划4个字就赶紧回来了。

    脑海中浮现了两个问题:
    为什么能用动态规划呢?用动态规划怎么解?

    先描述状态吧:

    f[i][j]表示word1中的[0,i] 与 word2中[0,j]的最少操作数。

    实际上这时候就能看出来了,当一个状态计算完成时,即一个状态的操作方案(决策)确定时,不影响后面状态的最优决策。即满足动态规划要求的无后效性,否则不能用动规来解决啦,因为要涉及到回溯修改前面的决策。也就是满足两个条件:1. 重叠子问题 2.最优子结构

    动态规划原理
    虽然已经用动态规划方法解决了上面两个问题,但是大家可能还跟我一样并不知道什么时候要用到动态规划。总结一下上面的斐波拉契数列和钢条切割问题,发现两个问题都涉及到了重叠子问题,和最优子结构。

    ①最优子结构

    用动态规划求解最优化问题的第一步就是刻画最优解的结构,如果一个问题的解结构包含其子问题的最优解,就称此问题具有最优子结构性质。因此,某个问题是否适合应用动态规划算法,它是否具有最优子结构性质是一个很好的线索。使用动态规划算法时,用子问题的最优解来构造原问题的最优解。因此必须考查最优解中用到的所有子问题。

    ②重叠子问题

    在斐波拉契数列和钢条切割结构图中,可以看到大量的重叠子问题,比如说在求fib(6)的时候,fib(2)被调用了5次,在求cut(4)的时候cut(0)被调用了4次。如果使用递归算法的时候会反复的求解相同的子问题,不停的调用函数,而不是生成新的子问题。如果递归算法反复求解相同的子问题,就称为具有重叠子问题(overlapping subproblems)性质。在动态规划算法中使用数组来保存子问题的解,这样子问题多次求解的时候可以直接查表不用调用函数递归。

    显然,状态转移方程也就出来了:

    f[i][j] 的计算分为两种情况:

    1. 当word1[i] == word2[j] 说明此时不需要任何操作,f[i][j] = f[i-1][j-1]
    2. else f[i][j] = min(f[i-1][j-1] , f[i-1][j] , f[i][j-1] ) + 1 , 此时,f[i][j] 可由之前已经确定的三个状态而来(因为有三种操作),如果是word1替换操作,则之前的状态为f[i-1][j-1];word1删除操作,则之前的状态为: f[i-1][j],此时就是删除word[i];word1插入操作,则之前的状态为:f[i][j-1],此时实际上就是在word[i]后面插入word2[j]

    那初始条件呢?当一方为空时,最少操作数就是另一个word的size了

    for (int i = 0; i <= m; i++) {
                f[i][0] = i;
            }
            for (int j = 0; j <= n; j++) {
                f[0][j] = j;
            }
    

    1A代码

    class Solution {
        public int minDistance(String word1, String word2) {
            int m = word1.length();
            int n = word2.length();
            if (m == 0) {
                return n;
            }
            if (n == 0) {
                return m;
            }
            int[][] f = new int[m + 1][n + 1];
            for (int i = 0; i <= m; i++) {
                f[i][0] = i;
            }
            for (int j = 0; j <= n; j++) {
                f[0][j] = j;
            }
    
            for (int i = 1; i <= m; i++) {
                for (int j = 1; j <= n; j++) {
                    if (word1.charAt(i - 1) == word2.charAt(j - 1)) {
                        f[i][j] = f[i - 1][j - 1];
                    } else {
                        f[i][j] = Collections.min(Arrays.asList(f[i - 1][j - 1], f[i - 1][j], f[i][j - 1])) + 1;
                    }
                }
            }
    
            return f[m][n];
        }
    }
    
  • 相关阅读:
    【区间DP】低价回文
    【二分图】文理分班
    【线型DP】洛谷P2066 机器分配
    电路原理 —— 电路基本概念和电路定律(1)
    数据结构(1) —— 绪论
    静电场 —— 电通量 高斯定理
    电路原理 —— 三相电路(1)
    静电场 —— 电场 电场强度
    静电场 —— 电荷 库伦定律
    Python——jieba库初使用
  • 原文地址:https://www.cnblogs.com/acbingo/p/9369297.html
Copyright © 2020-2023  润新知