动态规划——edit-distance 计算字符串的相似度

来源:互联网 发布:吃喝玩乐软件哪个好 编辑:程序博客网 时间:2024/06/05 05:41

题目描述

求两个字符串的编辑距离:

具体操作方法为:

a) Insert a character
b) Delete a character
c) Replace a character

比如,对于“abcd”和"abcde"可以认为最少需要通过增加/减少一个'e'得到,则编辑距离为1。


思路:

若第一个字符是相同的,则考虑两个字符串从第二个字符开始的相似距离即可;

若第一个字符不同,可以选择的方法有:

1.删除A串第一个字符,然后计算A[2,.....lenA]和B[1,......lenB]的距离;

2.删除B串第一个字符,然后计算A[1,.....lenA]和B[2,......lenB]的距离;

3.修改A串的第一个字符为B串的第一个字符,然后计算A[2,.....lenA]和B[2,......lenB]的距离;

4.修改B串的第一个字符为A串的第一个字符,然后计算A[2,.....lenA]和B[2,......lenB]的距离;

5.增加B串的第一个字符到A串第一个字符之前,然后计算A[1,.....lenA]和B[2,......lenB]的距离;

6.增加A串的第一个字符到B串第一个字符之前,然后计算A[2,.....lenA]和B[1,......lenB]的距离;


可以看出都是:

1.一步操作后,再将A[2,.....lenA]和B[1,......lenB]变为相同的字符串;

2.一步操作后,再将A[1,.....lenA]和B[2,......lenB]变为相同的字符串;

3.一步操作后,再将A[2,.....lenA]和B[2,......lenB]变为相同的字符串;


递归程序:

public class Solution {   public int minDistance(String word1, String word2) {          if(word1.length() == 0)//递归边界时的情况;                  return word2.length();           if(word2.length() == 0)                  return word1.length();                    if(word1.charAt(0) == word2.charAt(0))              return minDistance(word1.substring(1),word2.substring(1));                        int a=minDistance(word1.substring(1),word2.substring(1));              int b=minDistance(word1.substring(1),word2);              int c=minDistance(word1,word2.substring(1));                    return min(a,b,c)+1;      }       public int min(int a,int b,int c)              {              int min=a<b?a:b;              return min<c?min:c;          }  }
DP:

如果我们用 i 表示当前字符串 A 的下标,j 表示当前字符串 B 的下标。 如果我们用d[i, j] 来表示A[1, ... , i] B[1, ... , j] 之间的最少编辑操作数。那么我们会有以下发现:

1. d[0, j] = j;

2. d[i, 0] = i;

3. d[i, j] = d[i-1, j - 1] if A[i] == B[j]

4. d[i, j] = min(d[i-1, j - 1], d[i, j - 1], d[i-1, j]) + 1  if A[i] != B[j]

找出最小编辑操作数,从底自上判断

public class Solution {    public int minDistance(String s1, String s2) {       //dp[i][j]表示s1长为i,s2长为j时的编辑距离;        int[][] dp=new int[s1.length()+1][s2.length()+1];        //S1长度为0时,返回s2的长度;        for(int i=0;i<=s1.length();i++)            {            dp[i][0]=i;        }        //s2长度为0时,返回s1的长度;        for(int j=0;j<=s2.length();j++)            {            dp[0][j]=j;        }        //一般情况        for(int i=1;i<=s1.length();i++)            {                        for(int j=1;j<=s2.length();j++)                {                //当s1第i个字符和s2第j个字符相同时:                if(s1.charAt(i-1) == s2.charAt(j-1))                    {                    dp[i][j]=dp[i-1][j-1];                }                //当s1第i个字符和s2第j个字符不同时:                else                    {                    //dp[i-1][j-1]为s1的第i个字符变换为s2的第j个字符或者s2变换的情况;                    //dp[i-1][j]为删除或插入的情况;                    dp[i][j]=min(dp[i-1][j-1],dp[i-1][j],dp[i][j-1])+1;                }            }        }        return dp[s1.length()][s2.length()];    }    public int min(int a,int b,int c)        {        int min=a<b?a:b;        return min<c?min:c;    }}




0 0