计算两个字符串的相似度---动态规划实现

问题描述:
把两个字符串变成相同的基本操作定义如下:
1.     修改一个字符(如把 a 变成 b)
2.     增加一个字符 (如 abed 变成 abedd)
3.     删除一个字符(如 jackbllog 变成 jackblog)
针对于 jackbllog到jackblog 只需要删除一个或增加一个 l 就可以把两个字符串变为相同。把这种操作需要的次数定义为两个字符串的距离 L, 则相似度定义为1/(L+1) 即距离加一的倒数。那么jackbllog和jackblog的相似度为 1/1+1=1/2=0.5 也就是所两个字符串的相似度是 0.5。
给定任意两个字符串,你是否写出一个是否来计算出它们的相识度。
分析题目:本题是一个多级阶段的决策问题,每个阶段的最优选择会受到前面最优选择的影响,我们可以利用动态规划来实现,1,定义一个子问题,2,确定子问题最优解的堆叠方式。
以本题为例,假设source字符串有n个字符,target字符串有m个字符,如果将问题定义为求解将source的1-n个字符转换为target的1-m个字符所需要的最少编辑次数(最小编辑距离),则其子问题就可以定义为将source的1-i个字符转换为target的1-j个字符所需要的最少编辑次数,这就是本问题的最优子结构。我们用d[i, j]表示source[1..i]到target[1..j]之间的最小编辑距离,则计算d[i, j]的递推关系可以这样计算出来:
 
如果source[i] 等于target[j],则:
 
d[i, j] = d[i-1, j-1] + 0                                               (递推式 1)
 
如果source[i] 不等于target[j],则根据插入、删除和替换三个策略,分别计算出使用三种策略得到的编辑距离,然后取最小的一个:
 
d[i, j] = min(d[i, j - 1] + 1,d[i - 1, j] + 1,d[i - 1, j - 1] + 1 )            (递推式 2)
 
d[i, j - 1] + 1 表示对source[i]执行插入操作后计算最小编辑距离
d[i - 1, j] + 1 表示对source[i]执行删除操作后计算最小编辑距离
d[i - 1, j - 1] + 1表示对source[i]替换成target[i]操作后计算最小编辑距离
 
d[i, j]的边界值就是当target为空字符串(m = 0)或source为空字符串(n = 0)时所计算出的编辑距离:
 
m = 0,对于所有 i:d[i, 0] = i
n = 0,对于所有 j:d[0, j] = j
 
        根据前面分析的最优子结构、最优解的递推关系以及边界值,写出用动态规划法求解最小编辑距离的算法就很容易了,以下代码就是计算两个字符串的最小编辑距离的算法实现:

  1. public class Main{
  2. public int fun(String source,String target){
  3. int i,j;
  4. int[][] d = new int[source.length()+1][target.length()+1];
  5. for(i=1;i<source.length()+1;i++){/*初始化临界值*/
  6. d[i][0]=i;
  7. }
  8. for(j=1;j<target.length()+1;j++){/*初始化临界值*/
  9. d[0][j]=j;
  10. }
  11. for(i=1;i<source.length()+1;i++){/*动态规划填表*/
  12. for(j=1;j<target.length()+1;j++){
  13. if(source.substring(i-1, i).equals(target.substring(j-1, j))){
  14. d[i][j]=d[i-1][j-1];/*source的第i个和target的第j个相同时*/
  15. }else{/*不同的时候则取三种操作最小的一个*/
  16. d[i][j]=min(d[i][j-1]+1,d[i-1][j]+1,d[i-1][j-1]+1);
  17. }
  18. }
  19. }
  20. return d[source.length()][target.length()];
  21. }
  22. private int min(int i, int j, int k) {
  23. int min = i<j?i:j;
  24. min = min<k?min:k;
  25. return min;
  26. }
  27. public static void main(String[] args) {
  28. StringSimilar ss = new StringSimilar();
  29. System.out.println(ss.fun("SNOWY", "SUNNY"));//3
  30. System.out.println(ss.fun("a", "b"));//1
  31. System.out.println(ss.fun("abdd", "aebdd"));//1
  32. System.out.println(ss.fun("travelling", "traveling"));//1
  33. }
  34. }

总结:

注解:
【1】最优子结构:对于多阶段决策问题,如果每一个阶段的最优决策序列的子序列也是最优的,且决策序列具有“无后效性”,就可以将此决策方法理解为最优子结构。
 
【2】无后效性:动态规划法的最优解通常是由一系列最优决策组成的决策序列,最优子结构就是这些最优决策序列中的一个子序列,对于每个子序列再做最优决策会产生新的最优决策(子)序列,如果某个决策只受当前最优决策子序列的影响,而不受当前决策可能产生的新的最优决策子序列的影响,则可以理解这个最优决策具有无后效性。

时间: 2024-11-10 16:37:20

计算两个字符串的相似度---动态规划实现的相关文章

比较字符串总结:如果计算两个字符串的相似度或者距离

有关字符串相关比较问题,一般处理方法都选择动态规划处理方法.或者是单个循环,或者是多个循环:dp 遇到这种两个串的问题,很容易想到DP.但是这道题的递推关系不明显.可以先尝试做一个二维的表int[][] dp,用来记录匹配子序列的个数(以S="rabbbit",T = "rabbit"为例): r a b b b i t 1 1 1 1 1 1 1 1 r 0 1 1 1 1 1 1 1 a 0 0 1 1 1 1 1 1 b 0 0 0 1 2 3 3 3 b 0

编程之美3.3 计算两个字符串的相似度

      假如有两个字符串分别是:abcd,bbcd,那么,这两个字符串不相同的字符个数是1,即第一个字符时不相同的,定义字符串的相似度为 1 / (x + 1),其中,x 就是不相同的字符个数.       我们可以有三种方法比较两个字符串中不相同字符的个数:       1.去掉第一个字符串中不相同的那个字符,并同时再去比较下一个字符       2.去掉第二个字符串中不相同的那个字符,并同时再去比较下一个字符       3.同时去掉字符串中不相同的那个字符,并同时再去比较下一个字符  

C#通过编辑距离计算两个字符串的相似度的代码

将开发过程中较好的一些代码段备份一下,下面的代码是关于C#通过编辑距离计算两个字符串的相似度的代码,应该能对码农们有些帮助. using System; using System.Text.RegularExpressions; using System.Threading.Tasks; namespace Levenshtein { public delegate void AnalyzerCompletedHander(double sim); public class Levenshtei

fuzzywuzzy:计算两个字符串之间的相似度

楔子 fuzzywuzzy是用来计算两个字符串之间的相似度的,它是依据Levenshtein Distance算法来进行计算的 Levenshtein Distance 算法,又叫 Edit Distance 算法,是指两个字符串之间,由一个转成另一个所需的最少编辑操作次数.许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符.一般来说,编辑距离越小,两个串的相似度越高. fuzz from fuzzywuzzy import fuzz # 调用fuzz.ratio即可计算两

C#比较两个字符串的相似度【转】

原文地址:http://www.2cto.com/kf/201202/121170.html 我们在做数据系统的时候,经常会用到模糊搜索,但是,数据库提供的模糊搜索并不具备按照相关度进行排序的功能. 现在提供一个比较两个字符串相似度的方法.通过计算出两个字符串的相似度,就可以通过Linq在内存中对数据进行排序和筛选,选出和目标字符串最相似的一个结果. 本次所用到的相似度计算公式是 相似度=Kq*q/(Kq*q+Kr*r+Ks*s) (Kq > 0 , Kr>=0,Ka>=0)其中,q是字

计算两个字符串最大公有子串

*:first-child { margin-top: 0 !important; } body>*:last-child { margin-bottom: 0 !important; } /* BLOCKS =============================================================================*/ p, blockquote, ul, ol, dl, table, pre { margin: 15px 0; } /* HEAD

使用MinHash算法计算两个集合的相似度

集合相似度计算是一个常见的问题.例如,已知看过芈月传的人都有哪些,还知道看过琅琊榜的人都有哪些,那么想知道同时看过两者的人群占至少看过一部的人群的占比,就是求这两个集合的相似度: 集合A = 看过芈月传的人群集合B = 看过琅琊榜的人群相似度 = |A∩B| / |A∪B| = 既看过芈月传又看过琅琊榜的人数 / 看过芈月传或琅琊榜的人数 当集合的元素较少时,我们可以采用逐一比较的方式来找出既在集合A出现也在集合B出现的人,统计其人数,再除以至少在集合A或集合B出现的人数,得到相似度. 然而当集

EditDistance,求两个字符串最小编辑距离,动态规划

问题描述: 题目描述Edit DistanceGiven 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    

计算两个字符串类型的时间差

import java.text.SimpleDateFormat; import java.util.Date; /** * @author libin * @date 2018/12/14 15:12:13 */ public class Demo { public static void main(String[] args) { // 计算时间差 System.out.println(CalTime("15:05", "14:35")); } // 计算两个