Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2. (each operation is counted as 1 step.)

You have the following 3 operations permitted on a word:

a) Insert a character

b) Delete a character

c) Replace a character

听人家说,这是 双序列DP问题. 确实,对我来说,这个题的解法好难理解,即使之前做出了几个dp问题.我怎么可能说自己笨呢!

四个优秀的解释:

http://www.stanford.edu/class/cs124/lec/med.pdf

http://www.cnblogs.com/pandora/archive/2009/12/20/levenshtein_distance.html

http://www.jianshu.com/p/39115986db5a

http://www.dreamxu.com/books/dsa/dp/edit-distance.html

一个分治、dp、贪心的优秀小 book:

http://www.dreamxu.com/books/dsa/dc/subset.html

看了人家很多解释,还是自己想出个例子,自己再顺一遍才能较好的理解.Come on!

假设有 3 种操作:

插入,删除 和 修改.假设它们的 cost 均为 1;

注意有的题目可能它们的 cost 不相同, 比如:

  • The costs of both insertion(插入) and deletion(删除) are same value, that is 1;
  • The cost of substitution(替换) is 2.

咱自己的例子:

说例子前需说明什么是 dp[i, j].

dp[i, j] 称为 s1[0..i] 串到 s2[0..j] 的最小距离. 表示 字符串 s1[0..i] 转变成 s2[0..j] 的最小代价.在我们的题中,也可理解为最小步骤(因为无论啥操作,cost都是1).

这句话当初对我来说并不好理解.为了更容易的让大家理解,举个例子:

本解释将跟随题目要求,cost 均为1.

符号 "*" 代表空字符串.

s1 = "a"
s2 = "b"

现在要把 s1 变成 s2,问:最少的步骤是多少? 显然,这种情况下,凭直觉,肯定是1步,既, 1步 substitution.

此时:

这是要对 s1 做 substitution 操作, 将 a 替换成 b:
dp[i, j] = dp[i-1, j-1] + 1 = dp[0, 0] + 1 = 0 + 1 = 1;
若 s1 的第一个字符 a 和 s2 的第一个字符一样的话: dp[1, 1] = dp[0, 0] = 0, 就不需要替换操作了. * a
^
i=1 * b
^
j=1

dp[i = 1, j = 1] 可以写成 dp[i = 0, j = 0] + 1. 就是 s1[0..1] 的串变成 s2[0..1] 的串可表示成 s1的空串变成s2的空串所需次数 + 1.

空串变空串?那还用变?精神病的做法是 * -> a ->*,这个cost = 2, 而dp里存的是最小次数或叫做最下距离,那么显然 dp[i = 0, j = 0] = 0 (空串变空串?两个空串有什么好变化的,对吧)

但真的只有这一种办法吗?不是的.看下面:

这是 s1由空变为b 步骤数已知的情况下, 再删除a:
dp[i, j] = dp[i-1][j] + 1 = 1 + 1 = 2 * a
^
i-1=0 * b
^
j=1

还有一个情况:

这是 s1="a" ,删除a变成空的步骤数已知的情况下,再在最后面插入一个b:
dp[i, j] = dp[i][j-1] + 1 = dp[1][0] + 1 = 1 + 1 = 2 * a
^
i=1 * b
^
j-1=0

dp[i, j]只与其左上,左,上,有关.分别为 dp[i-1,j-1], dp[i,j-1] and dp[i-1,j].

总结起来步骤是这样的:

  1. m = s1 的长度, n = s2 的长度;
  2. 初始化边界:dp[0][j] = j, dp[i][0] = i,其中i = [0,..,m], j = [0,..,n]. 就是空串变某个串, 或某个串变空串的步骤数,肯定是那个串的长度了;
  3. s1[i - 1] = s2[j - 1], 则dp[i][j] = min(dp[i - 1][j - 1], min(dp[i - 1][j] + 1, dp[i][j - 1] + 1)); 这表示若dp[i - 1][j - 1], dp[i - 1][j]+1, dp[i][j - 1]+1 已知, 则由这3种 case所表达的状态 到 dp[i][i]的状态.我们取上述三种状态的最小值赋值给dp[i][j]. 其中dp[i - 1][j - 1]不用加1是因为s1和s2最后一个字符是一样的,当然不用再加1,否则+1(就是修改s1最后字符为s2最后字符,其实说最后字符是不妥当的,我们直接认为当前正在处理s1,s2最后面的那个字符,这么想能使问题简单一些.)
  4. s1[i - 1] != s2[j - 1], 则dp[i][j] = min(dp[i - 1][j - 1] + 1, min(dp[i - 1][j] + 1, dp[i][j - 1] + 1)); 注意,除了dp[i - 1][j - 1] + 1有变化外,其他没变.
  5. 空间复杂度问题:我们可以维护一个(m+1) * (n+1) 的 dp 矩阵,另一种更好的办法是只维护一个 m 或 n 大小的数组.

人家想法,咱的代码:

方法一:

\(O(m*n)\) time, \(O(m*n)\) extra space.

int minDistance(string word1, string word2) {
int m = word1.length(), n = word2.length(); // dp: a (m+1) * (n+1) matrix
vector < vector<int> > dp(m + 1, vector<int>(n + 1, 0)); // fill values in boundary
for (int i = 0; i <= m; i++)
dp[i][0] = i;
for (int j = 0; j <= n; j++)
dp[0][j] = j; // dp state transfer formula
for (int i = 1; i <= m; i++)
for (int j = 1; j <= n; j++)
if (word1[i - 1] == word2[j - 1])
dp[i][j] = min(dp[i - 1][j - 1],
min(dp[i - 1][j] + 1, dp[i][j - 1] + 1));
else
dp[i][j] = min(dp[i - 1][j - 1] + 1,
min(dp[i - 1][j] + 1, dp[i][j - 1] + 1)); return dp[m][n];
}

方法二:

\(O(m*n)\) time, \(O(m)\) extra space.

墨迹了挺长时间,没写出来.

看人家的吧.https://leetcode.com/problems/edit-distance/discuss/

写本文的时候发现,文字描述起来好费劲,啰里啰嗦,自己写作水平根本不行啊.

72. Edit Distance(困难,确实挺难的,但很经典,双序列DP问题)的更多相关文章

  1. 【Leetcode】72 Edit Distance

    72. Edit Distance Given two words word1 and word2, find the minimum number of steps required to conv ...

  2. 刷题72. Edit Distance

    一.题目说明 题目72. Edit Distance,计算将word1转换为word2最少需要的操作.操作包含:插入一个字符,删除一个字符,替换一个字符.本题难度为Hard! 二.我的解答 这个题目一 ...

  3. [LeetCode] 72. Edit Distance 编辑距离

    Given two words word1 and word2, find the minimum number of operations required to convert word1 to  ...

  4. 72. Edit Distance

    题目: Given two words word1 and word2, find the minimum number of steps required to convert word1 to w ...

  5. leetCode 72.Edit Distance (编辑距离) 解题思路和方法

    Edit Distance Given two words word1 and word2, find the minimum number of steps required to convert  ...

  6. [LeetCode] 72. Edit Distance(最短编辑距离)

    传送门 Description Given two words word1 and word2, find the minimum number of steps required to conver ...

  7. 72. Edit Distance *HARD*

    Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2 ...

  8. LeetCode - 72. Edit Distance

    最小编辑距离,动态规划经典题. Given two words word1 and word2, find the minimum number of steps required to conver ...

  9. 【一天一道LeetCode】#72. Edit Distance

    一天一道LeetCode 本系列文章已全部上传至我的github,地址:ZeeCoder's Github 欢迎大家关注我的新浪微博,我的新浪微博 欢迎转载,转载请注明出处 (一)题目 Given t ...

随机推荐

  1. 租户、租户管理员、部门管理员和开发者在APIGW中的角色

    一.参与者 1.vdcId:租户 2.运营管理员 operator: 一种角色 创建开发商 审批外置服务,如:hadoop集群 审批内置服务,如:<API使用申请> 3.租户管理员     ...

  2. hadoop原理

    MapReduce工作原理图文详解 前言:   前段时间我们云计算团队一起学习了hadoop相关的知识,大家都积极地做了.学了很多东西,收获颇丰.可是开学后,大家都忙各自的事情,云计算方面的动静都不太 ...

  3. 阿里安全归零实验室招聘各路大牛!offer好说!

    阿里安全归零实验室成立于2017年11月,致力于对黑灰产技术的研究.实验室的愿景是通过技术手段解决当前日益严重的网络违规和网络犯罪问题,为阿里新经济体保驾护航. 实验室与寄生在阿里生态经济体的黑灰产直 ...

  4. Tess4J OCR简单使用教程

    Tess4J简介 Tesseract-OCR支持中文识别,并且开源和提供全套的训练工具,是快速低成本开发的首选.而Tess4J则是Tesseract在Java PC上的应用.在英文和数字识别中性能还是 ...

  5. 前端之HTML内容

    一.HTML介绍 1.Web服务本质 当我们在浏览器中输入一个url后打开一个页面这个过程实质是一个网络编程中的sockt服务端接受指令并发送指令的一个过程.本质顺序是: 浏览器发请求——>HT ...

  6. SSM中的登陆验证码

    @Autowired private Producer captchaProducer = null; /** * 后台登录验证码 * @param request * @param response ...

  7. 为什么Java不能以返回值区分重载方法?

    读者可能会想:"在区分重载方法的时候,为什么只能以类名和方法的形参列表作为标准呢?能否考虑用方法的返回值来区分呢?" 比如下面两个方法,虽然他们有相同的名字和形式参数,但却很容易区 ...

  8. python基础——多态与多态性

    python基础--多态与多态性 1 多态 多态指的是一类事物有多种形态,(一个抽象类有多个子类,因而多态的概念依赖于继承) 1. 序列类型有多种形态:字符串,列表,元组. 2. 动物有多种形态:人, ...

  9. Hive:有表A与表B进行inner join,如果A分组内包含有数据,使用A,否则使用B分组下的数据

    tommyduan_fingerlib 指纹库 栅格小区级别数据tommyduan_mr_grid_cell_result_all 统计 栅格小区级别数据业务:以tommyduan_mr_grid_c ...

  10. c语言一个显示星号的函数(隐藏密码)

    显示星号 void star(char p[])    //显示星号 {     int j; while((p[j] = getch())!='\r') { if(p[j] !='\b') { pr ...