一个原始字符串,经过不断的修改,删除最后变成另外一个字符串,怎么体现出这个字符串的修改痕迹呢,这里面有个最小路径的概念,也就是原始字符串->目标字符串最少要经过多少步骤
假设原字符串:src="abCd";
假设新字符串:dst="ABCD";
那么从abCd->ABCD最少需要经过多少步呢?
首先,我们先画个矩阵图形来加深理解,如下图
1234表示字符串中每一个字符对应的位置,不一定原始字符串就跟目标字符串一样长,有可能原始字符串比目标字符串长,也可能短,这里为了方便演示就选择了一样长
tmp为中间值,为了后面的计算
然后开始算法,这个算法是哪位数据家提出来的我忘记了,有知道的小伙伴可以留言告知下哈
其中有个最小值的概念,以4个小正方形为一组,我们先算出第一个格子的值,如下图
上面红框框出来的小正方形中的2怎么算出来的呢,可以看个式子:"a" == "A" ? 0 : 2, 这个式子的意思就是字符串a是否等于字符串A,如果相等,那么结果等于0,如果不等,结果等于2,这里的0跟2可以随意定义,只是为了区分.
然后这里就有3个值,分别为
起始值=0,a=1,A=1,tmp=2,
起始值+tmp=2, a+1=2, A+1=2 算出来的3个值中最小的一个值为2,这就是最小值的概念
接着算出右边第二个格子的值,如下图所示:
按照刚才的算法我们再来算一次,字符串"b"是否等于字符串"B",结果为false,那么tmp=2,
现在4个小正方形的其他3个值为:a=1,b=2,A=2,然后a+tmp=3,b+1=3,A+1=3,最小值就是3
按照这个方式一直算下去...
.
.
来到第二行的第一个值,还是一样的,上图中红框框出的小正方形中已知的3个值分别是A=1,B=2,a=2,
"a" == "B" ? 0 : 2 结果tmp=2, 那么 A+tmp=3,B+1=3,a+1=3,最小值是3
到了这里大家也许会说算出来的几个值都是相等的呀,这是因为这里给的例子比较简单,继续算下去就知道了
.
.
不同的地方就在这里了,这一步是算到原始字符串中的"C"和目标字符串中的"C"做比较,还是按照上面的算法
这时小正方形里已知的3个值分别是:
"C" == "C" ? 0 : 2 tmp=0,这里"C" == "C" 结果为true,所以tmp=0
然后4+tmp=4,C+1=6,C+1=6,最小值就是4了
我们按照这个算法先把矩阵填满,如下图所示:
上图所示的图形,就是我们算出来的原始字符串src="abCd"到目标字符串dst="ABCD"的编辑距离矩阵
矩阵中,右下角的6标识原始字符串"abCd"->"ABCD"最少需要编辑6次
下一步,我们来根据这个距离矩阵来推导出编辑路径,还是以4个小正方形为一组,从右下角推导至左上角,如下图所示:
这里也有一个最小值,这里的最小值是通过上图所示红框中带红点的3个值中最小的一个值
上图所示红框中最小值tmp=4,然后这个最小值要跟这个红框中其他3个值一一比较,比较出来的结果按照以下方式归类
tmp == 右上角的值 ? 向上回溯
tmp == 左下角的值 ? 向左回溯
tmp == 右下角的值 ? 向左上回溯
如果tmp都不等于他们的任何一个,那么就用左下角的值跟右上角的值比较
右上角的值 <= 左下角的值 ? 向上回溯 : 向左回溯
按照上面的规则,我们先来算下上图中红框的结果
已经算出上图红框中的最小值tmp=4,因为tmp不等于任何一个,所以继续比较左下角的值跟右上角的值
因为左下角的值为5,右上角的值为5,
所以 "右上角的值 <= 左下角的值 ? 向上回溯 : 向左回溯" 在这个表达式中的结果是true,所以第一步是向上回溯,如下图所示:
这个时候,我们的起点就停留在了上图中红框里右下角的位置,继续按照刚才的方法推导
先算出左上角,右上角,左下角3个值中的最小值,也就是,5,6,4中的最小值,tmp=4
可以看出tmp == 左下角的值,那就是向左回溯,如下图:
这个时候,我们的起点就在上图所示红框中的右下角位置,继续按照刚才的方法
4,5,5,中最小值tmp=4,等于右下角的值,向左上回溯,如下图:
这个时候的起点就在上图中红框的右下角,继续按照刚才的方法推导下去,最终如下图:
到这里,也许会有小伙伴问,不是算出来从原始字符串到目标字符串最少有6步么,怎么图中会有7个箭头,别急,我们按照反向推导出来的路径,正向再推导一次
第一步:从0,0->0,1,原字符串删除了"a"字符 (左移删除)
第二步:从0,1->0,2,原字符串删除了"b"字符 (左移删除)
第三步:从0,2->1,2,原字符串增加了"A"字符 (下移增加)
第四步:从1,2->2,2,原字符串增加了"B"字符 (下移增加)
第五步:从2,2->3,3,原字符串中"C"字符保持不变,不计算步骤,所以步数还是从第五步开始 (右下移,不变)
第五步:从3,3->4,3,原字符串删除了"d"字符 (左移删除)
第六步:从4,3->4,4,原字符串增加了"D"字符 (下移增加)
所以原始字符串"abCd"->目标字符串"ABCD"就是经过了上面的6个步骤变化而来
到这里,我们编辑距离矩阵已经讲完了,大家可以根据上面讲述的方法去测试任何2个字符串算出他们之间的编辑路径
附上java如何使用编辑距离矩阵的原理,体现出修改痕迹的效果,如下图所示