标签:
字符串的相似度定义为:将一个字符串转换成另外一个字符串时需要付出的代价。转换可以采用插入、删除和替换三种编辑方式,因此转换的代价就是对字符串的编辑次数。
作为对比采用两种方式:递归算法和动态规划算法
朴素递归方式实现:朴素递归方式很清晰,很简洁,但是时间复杂度很高
public static int editDistance(String srcStr,String destSrc,int srcStart,int descStart) { //如果任意一个字符串结束,则返回 if((srcStr.length()-srcStart)==0 || (destSrc.length()-descStart)==0) { return Math.abs((srcStr.length()-srcStart)-(destSrc.length()-descStart)); } if(srcStr.charAt(srcStart)==destSrc.charAt(descStart)) { return editDistance(srcStr,destSrc,srcStart+1,descStart+1); } int edIns=editDistance(srcStr,destSrc,srcStart,descStart+1)+1;//插入字符 int edDel=editDistance(srcStr,destSrc,srcStart+1,descStart)+1;//删除字符 int edRep=editDistance(srcStr,destSrc,srcStart+1,descStart+1)+1;//替换字符 int min1=edIns>edDel?edDel:edIns; return min1>edRep?edRep:min1; }
现在考虑用动态规划的方法进行改进。首先定义出问题的状态,从状态转换关系开始定义阶段和子问题的递推关系。
假设如果将问题定义为求解source的[1.....n]个字符转换为target[1.....m]个字符所需要的最少编辑次数(编辑距离),则子问题就可以定义为将source[1......i]个字符转换为target[1......j]个字符所需要的最少编辑次数,这就是本问题的最优子结构,因此我们将状态定义为从子串source[1......i]到子串target[1......j]之间的编辑距离。
朴素递归的方法之所以时间复杂度很高,是因为大量的状态是重复计算的。接下来引入备忘录概念,用一个二维表记录每个状态的值,递归过程中优先查找表。
/*改进的带有备忘录的递归方法*/ public static int editDistanceBetter(String srcStr,String destSrc,int srcStart,int descStart,TagMemoRecord[][] tRecords) { //首先查表 if(tRecords[srcStart][descStart].refCount!=0) { tRecords[srcStart][descStart].refCount++; return tRecords[srcStart][descStart].distance; } int distance=0; //如果任意一个字符串结束,则返回 if((srcStr.length()-srcStart)==0 || (destSrc.length()-descStart)==0) { distance=Math.abs((srcStr.length()-srcStart)-(destSrc.length()-descStart)); } else if(srcStr.charAt(srcStart)==destSrc.charAt(descStart)) { distance=editDistance(srcStr,destSrc,srcStart+1,descStart+1); } else { int edIns=editDistance(srcStr,destSrc,srcStart,descStart+1)+1;//插入字符 int edDel=editDistance(srcStr,destSrc,srcStart+1,descStart)+1;//删除字符 int edRep=editDistance(srcStr,destSrc,srcStart+1,descStart+1)+1;//替换字符 int min1=edIns>edDel?edDel:edIns; distance= min1>edRep?edRep:min1; } tRecords[srcStart][descStart].distance=distance; tRecords[srcStart][descStart].refCount=1; return distance; }
class TagMemoRecord { int distance; int refCount; public TagMemoRecord() { this.distance=-1; this.refCount=0; } }
标签:
原文地址:http://www.cnblogs.com/xtsylc/p/4722901.html