动态规划之编辑距离问题
问题描述:
对于序列S和T, 它们之间的距离定义为: 对二者其一进行几次以下操作: 1, 删除一个字符; 2, 插入一个字符; 3, 改变一个字符. 每进行一次操作, 计数增加1. 将S和T变为相等序列的最小计数就是两者的编辑距离(edit distance)或者叫相似度. 请给出相应算法及其实现.
分析:
假设序列S和T的长度分别为m和n, 两者的编辑距离表示为edit[m][n]. 则对序列进行操作时存在以下几种情况:
- a, 当S和T的末尾字符相等时, 对末尾字符不需要进行上述定义操作中(亦即"编辑")的任何一个, 也就是不需要增加计数. 则满足条件: edit[m][n] = edit[m - 1][n - 1].
- b, 当S和T的末尾字符不相等时, 则需要对两者之一的末尾进行编辑, 相应的计数会增加1.
- b1, 对S或T的末尾进行修改, 以使之与T或S相等, 则此时edit[m][n] = edit[m - 1][n - 1] + 1;
- b2, 删除S末尾的元素, 使S与T相等, 则此时edit[m][n] = edit[m - 1][n] + 1;
- b3, 删除T末尾的元素, 使T与S相等, 则此时edit[m][n] = edit[m][n - 1] + 1;
- b4, 在S的末尾添加T的尾元素, 使S和T相等, 则此时S的长度变为m+1, 但是此时S和T的末尾元素已经相等, 只需要比较S的前m个元素与T的前n-1个元素, 所以满足edit[m][n] = edit[m][n - 1] + 1;
- b5, 在T的末尾添加S的尾元素, 使T和S相等, 此时的情况跟b4相同, 满足edit[m][n] = edit[m - 1][n] + 1;
- c, 比较特殊的情况是, 当S为空时, edit[0][n] = n; 而当T为空时, edit[m][0] = m; 这个很好理解, 例如对于序列""和"abc", 则两者的最少操作为3, 即序列""进行3次插入操作, 或者序列"abc"进行3次删除操作.
所以, 以上我们不难推出编辑距离的动态规划方程为:
, 其中
所以, 字符串编辑距离的动态规划算法的递归实现可以用如下的Java代码表示:
1 public static int editDistance(String a, String b) { 2 if (a == null || b == null) { 3 return -1; 4 } 5 return editDistance(a, a.length() - 1, b, b.length() - 1); 6 } 7 8 public static int editDistance(String a, int m, String b, int n) { 9 if (m < 0 || n < 0) { 10 return 1; 11 } else if (a.charAt(m) == b.charAt(n)) { 12 return editDistance(a, m - 1, b, n - 1); 13 } else { 14 return Math.min(Math.min(editDistance(a, m - 1, b, n) + 1, editDistance(a, m, b, n - 1) + 1), editDistance(a, m - 1, b, n - 1) + 1); 15 } 16 }
UPDATE:
同时, 由编辑距离的动态规划方程我们可以看出, edit[m][n]可以由edit[m - 1][n - 1], edit[m - 1][n], edit[m][n - 1]得出, 而如果edit是一个二维数组的话, edit[m][n]可以由它的上, 左, 左上三个位置的元素通过条件判断得出. 亦即我们可以通过遍历二维数组, 然后通过回溯来计算当前值.
例如对于字符串S = "sailn"和T = "failing", 对二维数组进行初始化为:
m\n | f | a | i | l | i | n | g | |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
s | 1 | 1 | ||||||
a | 2 | |||||||
i | 3 | |||||||
l | 4 | |||||||
n | 5 |
因为S[0] = s, T[0] = f, 则S[0] != T[0], 则对应于上述二维矩阵, edit[1][1] = min(edit[0][0], edit[0][1], edit[1][0]) + 1即edit[1][1] = min(0, 1, 1) + 1即edit[1][1] = 0 + 1 = 1.
m\n | f | a | i | l | i | n | g | |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
s | 1 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
a | 2 | 2 | 1 | |||||
i | 3 | |||||||
l | 4 | |||||||
n | 5 |
而对于S[1] = a, T[1] = a, S[1] = T[1], 则对应于二维矩阵, edit[2][2] = edit[1][1], 所以edit[2][2] = 1. 所以按照这种规则, 将上述二维矩阵填满则如下:
m\n | f | a | i | l | i | n | g | |
0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | |
s | 1 | 1 | 2 | 3 | 4 | 5 | 6 | 7 |
a | 2 | 2 | 1 | 2 | 3 | 4 | 5 | 6 |
i | 3 | 3 | 2 | 1 | 2 | 3 | 4 | 5 |
l | 4 | 4 | 3 | 2 | 1 | 2 | 3 | 4 |
n | 5 | 5 | 4 | 3 | 2 | 2 | 2 | 3 |
所以, 两者的编辑距离为edit[m][n] = edit[5][7] = 3.
所以, 按照上述思路即动态规划的回溯解法的Java版本可以如下进行:
1 public static int editDistance(String a, String b) { 2 if (a == null || b == null) { 3 return -1; 4 } 5 int[][] matrix = new int[a.length() + 1][b.length() + 1]; 6 for (int i = 0; i < a.length() + 1; i++) { 7 for (int j = 0; j < b.length() + 1; j++) { 8 if (i == 0) { 9 matrix[i][j] = j; 10 } else if (j == 0) { 11 matrix[i][j] = i; 12 } else { 13 if (a.charAt(i - 1) == b.charAt(j - 1)) { 14 matrix[i][j] = matrix[i - 1][j - 1]; 15 } else { 16 matrix[i][j] = 1 + Math.min(Math.min(matrix[i - 1][j], matrix[i][j - 1]), matrix[i - 1][j - 1]); 17 } 18 } 19 } 20 } 21 return matrix[a.length()][b.length()]; 22 }
转载于:https://www.cnblogs.com/littlepanpc/p/7895810.html
动态规划之编辑距离问题相关推荐
- 动态规划求编辑距离 - 残阳似血的博客
动态规划求编辑距离 - 残阳似血的博客 动态规划求编辑距离 - 残阳似血的博客 动态规划求编辑距离 位于分类 自然语言处理 这两天在写一个简单的单词拼写检查器(Spell checker),本来求编辑 ...
- 动态规划解决编辑距离问题
动态规划解决编辑距离问题 问题描述: 编辑距离:是指两个字串之间,由一个转成另一个所需的最少编辑操作次数. 方法:动态规划 状态:F(i,j):word1的前i个字符与word2的前j个字符的编辑距离 ...
- 由动态规划计算编辑距离引发的思考
简单介绍 编辑距离算法: https://www.cnblogs.com/BlackStorm/p/5400809.html https://wizardforcel.gitbooks.io/the- ...
- 经典动态规划:编辑距离
点击关注上方"五分钟学算法", 设为"置顶或星标",第一时间送达干货. 转自面向大象编程 本期例题:LeetCode 72. Edit Distance 编辑距 ...
- 动态规划---最短编辑距离
描述: 设A和B是2个字符串.要用最少的字符操作将字符串A转换为字符串B.这里所说的字符操作包括: (1)删除一个字符; (2)插入一个字符: (3)将一个字符改为另一个字符. 将字符串A变换为字符串 ...
- 动态规划____编辑距离
#include <stdio.h> #include <string.h>#define INF -1 #define MAX 1010int map[MAX][MAX]; ...
- 55天 - 算法 - 动态规划 - 数组类 从前往后
//模板#include <iostream> #include <cstdio> #include <string> using namespace std;/* ...
- 经典动态规划:戳气球问题
点击上方蓝字设为星标 东哥带你手把手撕力扣~ 作者:labuladong 公众号:labuladong 若已授权白名单也必须保留以上来源信息 今天我们要聊的这道题「Burst Balloon」和之 ...
- java动态规划鸡蛋问题_动态规划系列/高楼扔鸡蛋问题.md · lipengfei/fucking-algorithm - Gitee.com...
# 经典动态规划问题:高楼扔鸡蛋 今天要聊一个很经典的算法问题,若干层楼,若干个鸡蛋,让你算出最少的尝试次数,找到鸡蛋恰好摔不碎的那层楼.国内大厂以及谷歌脸书面试都经常考察这道题,只不过他们觉得扔鸡蛋 ...
- 编辑距离(Edit Distance)
编辑距离是用于比较两个字符串或者符号序列之间距离的常用距离函数. 含义为:给定两个单词 word1 和 word2,计算出将 word1 转换成 word2 所使用的最少操作数,可以对一个单词进行如下 ...
最新文章
- 荣耀6 原生Android,荣耀6 (移动4G) 官方原生简约实用 流畅省电 杜比音效 网速显示-刷机之家...
- 哪本python入门书内容最详细-重磅 | 由浅入深的 AI 学习路线,最详细的资源整理!...
- 一步步完成jsRender + Spring MVC + Nginx前后端分离示例
- (Metro学习三)图片uri保存到本地图片库
- dedecms最新版本修改任意管理员漏洞
- TortoiseGit + GitHub 快速上手指南
- Django中提供了6种缓存方式
- SQL中where 1 = 1的用处
- 存储管理实验linux,07-存储管理器实验
- Go 大败!Google 宣布 Fuchsia 终端开发只支持 C/C++/Dart
- linux下安装cudnn
- Qt网络编程——TCP
- LeetCode 152. 乘积最大子序列(动态规划)
- 中琛源携手台江县积极践行山区青少年体育公益
- java-----抽象类与接口
- 比较感兴趣的几个VC2012/VC2013特性
- 如何使用QGIS下载Google地图的遥感影像
- Matlab遗传算法工具箱求函数最小值
- vue后台管理框架(iview + vue)
- Tomcat中文乱码解决
热门文章
- LinearLayout removeAllViews后再 addView页面不展示
- Flutter之路由系列之Navigator简析
- 手动连接mysql_手动实现与数据库的连接
- 美团猫眼电影Android模块化实战总结
- 大龄程序员失业后,看他们是如何破局突围的?
- python 直方图每个bin中的值_python – 如何获取直方图bin中的数据
- centos7部署两个mysql_基于Canal和Kafka实现MySQL的Binlog近实时同步
- 怎么判断间隙过渡过盈配合_圆柱销有2个标准,选型注意材料和热处理,特别是销孔的配合关系...
- map slice综合示例 go语言
- go-结构化,方法的创建以及使用