DP-从基础题理解动态规划问题(4)(编辑距离)

    编辑距离(Edit Distance),又称Levenshtein距离,是指两个字串之间,由一个转成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符,插入一个字符,删除一个字符。

       下图为计算字符“beauty”与“batyu”编辑距离的二维图解:

   

步骤详解:1)先建立一张二维表(矩阵),如上图所示。矩阵中(0,0)位置不对应字母。

 2)计算矩阵(1,1)位置(即:红圈1所在的置)的值,此处为方便描述,将该位置定义为A点。

A点的值需要由A点左上方、左边和上边的值共同决定。为方便描述先将A点所需要的三个值赋给变量a,则a=(0,1,1)

A点对应的字母分别为(b,b),字母相同,则A点左上角的值加0(不同则加1),A点左边与上边的值分别加1。

此时a=(0,2,2),取a中做小值填入A点位置,见右图所示。

矩阵(1,2)位置(即:红圈2所在的位置),定义为B点。

B点赋值为b=(1,0,2)。由于B点对应的字母为(b,e),字母不同,则B点左上角的值加1,同时,B点左侧上侧分别加1。

此时b=(2,1,3),取b中最小值赋给B点。

3)按照步骤2)求出每个格子中的值。所有值求出后,右下角的值为最小编辑距离。

注意:不管上述步骤中的A点对应的字母(b,b)或B点对应的字母(b,e)是否相同,左侧和上侧都需要加1。

 对于序列S和T,它们之间距离定义为:对二者其一进行几次以下的操作(1)删去一个字符;(2)插入一个字符;(3)改变一个字符。每进行一次操作,计数增加1。将S和T变为同一个字符串的最小计数即为它们的距离。给出相应算法。

解法:

  将S和T的长度分别记为len(S)和len(T),并把S和T的距离记为m[len(S)][len(T)],有以下几种情况:

如果末尾字符相同,那么m[len(S)][len(T)]=m[len(S)-1][len(T)-1];

如果末尾字符不同,有以下处理方式

  修改S或T末尾字符使其与另一个一致来完成,m[len(S)][len(T)]=m[len(S)-1][len(T)-1]+1;

  在S末尾插入T末尾的字符,比较S[1...len(S)]和S[1...len(T)-1];

  在T末尾插入S末尾的字符,比较S[1...len(S)-1]和S[1...len(T)];

  删除S末尾的字符,比较S[1...len(S)-1]和S[1...len(T)];

  删除T末尾的字符,比较S[1...len(S)]和S[1...len(T)-1];

  总结为,对于i>0,j>0的状态(i,j),m[i][j] = min( m[i-1][j-1]+(s[i]==s[j])?0:1 , m[i-1][j]+1, m[i][j-1] +1)。

  这里的重叠子结构是S[1...i],T[1...j]。


import java.util.*;
public class 字符串相似度or编辑距离 {
	public static int min(int a,int b,int c) {
		int min=Integer.MAX_VALUE;
		if(a<min)
			min=a;
		if(b<min)
			min=b;
		if(c<min)
			min=c;
		return min;
	}
	public static void main(String[] args) {
		Scanner in=new Scanner(System.in);
		String[] s=new String[2];
		while(in.hasNext()) {
			s=in.nextLine().split(" ");
			String s1=s[0];
			String s2=s[1];
			int m=s1.length(),n=s2.length();
			int temp;      			//记录相同字符,不是0就是1
			char c1,c2;
			if(m==0||n==0)
				System.out.println(0);
			int[][] dp=new int[m+1][n+1];
			for(int i=0;i<=m;i++)     //初始化第一行
				dp[i][0]=i;
			for(int j=0;j<=n;j++)     //初始化第二行
				dp[0][j]=j;
			for(int i=1;i<=m;i++) {   //遍历两个字符串
				c1=s1.charAt(i-1);
				for(int j=1;j<=n;j++) {
					c2=s2.charAt(j-1);
					if(c1==c2)        //如果某一位置上的字符相同,不需要操作temp=0
						temp=0;
					else              //如果某一位置上的字符不同,需要操作temp=1
						temp=1;
					//找到每一步编辑变化的最小值
					dp[i][j]=min(dp[i-1][j]+1,dp[i][j-1]+1,dp[i-1][j-1]+temp);
				}
			}
			System.out.println(dp[m][n]);
		}
	}
}

猜你喜欢

转载自blog.csdn.net/zw159357/article/details/79646133