求两个字符串的编辑距离
2017-10-19 09:10
211 查看
原文
很多程序都需要利用到字符串的比较,而字符串的编辑距离在字符串相似性比较中,应用广泛。下面分享字符串编辑距离的求解。
字符串的编辑距离,又称为Levenshtein距离,由俄罗斯的数学家Vladimir Levenshtein在1965年提出。是指利用字符操作,把字符串A转换成字符串B所需要的最少操作数。其中,字符操作包括:
删除一个字符
插入一个字符
修改一个字符
例如对于字符串"if"和"iff",可以通过插入一个'f'或者删除一个'f'来达到目的。
一般来说,两个字符串的编辑距离越小,则它们越相似。如果两个字符串相等,则它们的编辑距离(为了方便,本文后续出现的“距离”,如果没有特别说明,则默认为“编辑距离”)为0(不需要任何操作)。不难分析出,两个字符串的编辑距离肯定不超过它们的最大长度(可以通过先把短串的每一位都修改成长串对应位置的字符,然后插入长串中的剩下字符)。
给定两个字符串A和B,求字符串A至少经过多少步字符操作变成字符串B。
1)首先考虑A串的第一个字符
假设存在两个字符串A和B,他们的长度分别是lenA和lenB。首先考虑第一个字符,由于他们是一样的,所以只需要计算A[2...lenA]和B[2...lenB]之间的距离即可。那么如果两个字符串的第一个字符不一样怎么办?可以考虑把第一个字符变成一样的(这里假设从A串变成B串):
修改A串的第一个字符成B串的第一个字符,之后仅需要计算A[2...lenA]和B[2...lenB]的距离即可;
删除A串的第一个字符,之后仅需要计算A[2...lenA]和B[1...lenB]的距离即可;
把B串的第一个字符插入到A串的第一个字符之前,之后仅需要计算A[1...lenA]和B[2...lenB]的距离即可。
2)接下来考虑A串的第i个字符和B串的第j个字符。
我们这个时候不考虑A的前i-1字符和B串的第j-1个字符。如果A串的第i个字符和B串的第j个字符相等,即A[i]=B[j],则只需要计算A[i...lenA]和B[j...lenB]之间的距离即可。如果不想等,则:
修改A串的第i个字符成B串的第j个字符,之后仅需要计算A[i+1...lenA]和B[j+1...lenB]的距离即可;
删除A串的第i个字符,之后仅需要计算A[i+1...lenA]和B[j...lenB]的距离即可;
把B串的第j个字符插入到A串的第i个字符之前,之后仅需要计算A[i...lenA]和B[j+1...lenB]的距离即可。
写到这里,自然会想到用递归求解或者动态规划求解,由于用递归会产生很多重复解,所以用动态规划。
用edit[i][j]表示A串从第i个字符开始和B串从第j个字符开始的距离。则从上面的分析,不难推导出动态规划方程:
,其中
(1)源串S有字符X,目标串T空白,即“S:字符X,T:空白”。要让S变成T,则意味着源串S要删除字符X,可得方程dp[i−1][j]+1。
(2)源串S空白,目标串T有字符Y,即“S:空白,T:字符Y”。要让S变成T,则意味着源串S要插入字符Y,可得方程dp[i][ j−1]+1。
(3)源串S中的字符X与目标串T中的字符Y对应,即“S:字符X,T:字符Y”。要让S变成T,则意味着要把源串S中的字符X替换成目标串T中的字符Y,可得方程dp[i−1][j−1]+(s[i] ==t[j]?0:1)。
综上所述,如果用dp[i][j]表示源串S[0..i]和目标串T[0..j]的最短编辑距离,则可以写出简单的深度优先状态方程:
dp[i][j]=min{dp[i−1][j]+1, dp[i][j−1]+1, dp[i−1][j−1]+(S[i]==T[j] ? 0 : 1) }
实际上,“编辑距离”问题在搜索引擎中有着重要的用途。例如,搜索引擎关键字查询中拼写错误的提示,如图5-2所示,当输入Jult后,因为没有Jult这个单词,所以搜索引擎猜测你可能是输入错误,继而会提示你是不是找July。
很多程序都需要利用到字符串的比较,而字符串的编辑距离在字符串相似性比较中,应用广泛。下面分享字符串编辑距离的求解。
概念
字符串的编辑距离,又称为Levenshtein距离,由俄罗斯的数学家Vladimir Levenshtein在1965年提出。是指利用字符操作,把字符串A转换成字符串B所需要的最少操作数。其中,字符操作包括:删除一个字符
插入一个字符
修改一个字符
例如对于字符串"if"和"iff",可以通过插入一个'f'或者删除一个'f'来达到目的。
一般来说,两个字符串的编辑距离越小,则它们越相似。如果两个字符串相等,则它们的编辑距离(为了方便,本文后续出现的“距离”,如果没有特别说明,则默认为“编辑距离”)为0(不需要任何操作)。不难分析出,两个字符串的编辑距离肯定不超过它们的最大长度(可以通过先把短串的每一位都修改成长串对应位置的字符,然后插入长串中的剩下字符)。
问题描述
给定两个字符串A和B,求字符串A至少经过多少步字符操作变成字符串B。
问题分析
1)首先考虑A串的第一个字符假设存在两个字符串A和B,他们的长度分别是lenA和lenB。首先考虑第一个字符,由于他们是一样的,所以只需要计算A[2...lenA]和B[2...lenB]之间的距离即可。那么如果两个字符串的第一个字符不一样怎么办?可以考虑把第一个字符变成一样的(这里假设从A串变成B串):
修改A串的第一个字符成B串的第一个字符,之后仅需要计算A[2...lenA]和B[2...lenB]的距离即可;
删除A串的第一个字符,之后仅需要计算A[2...lenA]和B[1...lenB]的距离即可;
把B串的第一个字符插入到A串的第一个字符之前,之后仅需要计算A[1...lenA]和B[2...lenB]的距离即可。
2)接下来考虑A串的第i个字符和B串的第j个字符。
我们这个时候不考虑A的前i-1字符和B串的第j-1个字符。如果A串的第i个字符和B串的第j个字符相等,即A[i]=B[j],则只需要计算A[i...lenA]和B[j...lenB]之间的距离即可。如果不想等,则:
修改A串的第i个字符成B串的第j个字符,之后仅需要计算A[i+1...lenA]和B[j+1...lenB]的距离即可;
删除A串的第i个字符,之后仅需要计算A[i+1...lenA]和B[j...lenB]的距离即可;
把B串的第j个字符插入到A串的第i个字符之前,之后仅需要计算A[i...lenA]和B[j+1...lenB]的距离即可。
写到这里,自然会想到用递归求解或者动态规划求解,由于用递归会产生很多重复解,所以用动态规划。
构建动态规划方程
用edit[i][j]表示A串从第i个字符开始和B串从第j个字符开始的距离。则从上面的分析,不难推导出动态规划方程:,其中
(1)源串S有字符X,目标串T空白,即“S:字符X,T:空白”。要让S变成T,则意味着源串S要删除字符X,可得方程dp[i−1][j]+1。
(2)源串S空白,目标串T有字符Y,即“S:空白,T:字符Y”。要让S变成T,则意味着源串S要插入字符Y,可得方程dp[i][ j−1]+1。
(3)源串S中的字符X与目标串T中的字符Y对应,即“S:字符X,T:字符Y”。要让S变成T,则意味着要把源串S中的字符X替换成目标串T中的字符Y,可得方程dp[i−1][j−1]+(s[i] ==t[j]?0:1)。
综上所述,如果用dp[i][j]表示源串S[0..i]和目标串T[0..j]的最短编辑距离,则可以写出简单的深度优先状态方程:
dp[i][j]=min{dp[i−1][j]+1, dp[i][j−1]+1, dp[i−1][j−1]+(S[i]==T[j] ? 0 : 1) }
/** * 计算两个字符串的编辑距离 * @param str1 需要比较的字符串 * @param str2 需要比较的字符串 * @return 两个字符串的编辑距离 */ public int editDistance(String str1,String str2){ int lenStr1=str1.length(); int lenStr2=str2.length(); int[][] edit=new int[lenStr1+1][lenStr2+1]; for(int i=1;i<=lenStr1;i++){ edit[i][0]=i; } for(int j=1;j<=lenStr2;j++){ edit[0][j]=j; } for(int i=1;i<=lenStr1;i++){ for(int j=1;j<=lenStr2;j++){ if(str1.charAt(i-1)==str2.charAt(j-1)){ edit[i][j]=edit[i-1][j-1]; }else{ edit[i][j]=Math.min(edit[i-1][j], edit[i][j-1],edit[i-1][j-1])+1; } } } return edit[lenStr1][lenStr2]; }
问题扩展
实际上,“编辑距离”问题在搜索引擎中有着重要的用途。例如,搜索引擎关键字查询中拼写错误的提示,如图5-2所示,当输入Jult后,因为没有Jult这个单词,所以搜索引擎猜测你可能是输入错误,继而会提示你是不是找July。相关文章推荐
- 两个字符串的编辑距离-动态规划方法
- 两个字符串的编辑距离、相似度求解
- 利用编辑距离(Edit Distance)计算两个字符串的相似度
- 求两个字符串的编辑距离
- 利用编辑距离(Edit Distance)计算两个字符串的相似度
- 编辑距离(LD)计算两个字符串相似度
- 计算两个字符串编辑距离
- [LeetCode]-Edit Distance 两个字符串之间最小编辑距离
- 两个字符串之间的最短编辑距离
- 基于动态规划(dynamic programming)的计算两个字符串的编辑距离
- 两个字符串的最小编辑距离 Edit Distance
- 编辑距离LCS算法详解:Levenshtein Distance算法计算两个字符串的相似度
- DP求两个字符串的编辑距离
- Edit Distance(编辑距离)算法。计算两个字符串的相似程度。
- 算两个字符串之间的编辑距离
- 计算两个字符串的编辑距离的快速算法
- 求两个字符串的最短编辑距离
- 求两个字符串的最长公共子串,最长公共子序列,编辑距离
- 求算两个字符串之间的编辑距离
- EditDistance,求两个字符串最小编辑距离,动态规划