动态规划主题专杀-编辑距离-思路自我解剖

做这种题再次强调一点,思路远比代码重要,思路对了,即使代码错了,错的也是细枝末节,思路错了,那就是个0.

所以本文并不想着重讲本题的算法代码,代码解法网上有得是。这里着重剖析自己的思路问题。

 

 

题干:

 

乍一看很没头绪的题目,但隐约感觉能用动态规划来做。首先动态规划你得找到迭代公式吧?得知道如何将原问题降级为一个更小的子问题吧?那么按照这种思路的话,假设两个字符串长度分别为M何N, 记所求答案为dp(M,N),那么自然要想办法降级到dp(X,Y),其中X<M, Y<N, 是吧?那怎么降呢?

 

反正以我笨拙的直觉还是难以第一时间想到,但是,但凡这种字符串的降级,总是可以从端点来思考,也可以从状态反向思考,例如当考虑字符串intention->execution这种变化在最后一步的时候,可能有哪些情况?根据题干定义,可能是替换了其中一个字符,axecution->execution,可能是插入了一个字符,例如从xecution->execution,也可能是删除了一个字符,executiobn->execution,并且这三种操作可能发生在字符串的任意位置,这就让人很蛋疼了,3中操作+任意位置,变数太大,不像是能解决问题的一个思路。有没有办法降低一点变数呢?

 

网上你可以搜到各种答案告诉你说先让倒数第一个字符相等,再让倒数第二个字符相等,这样逐个缩减规模。

 

这固然是动态规划的典型套路,可是问题来了,首先你TM告诉我为什么你会想用这种方法来降级?其次你TM证明给我看这种按顺序匹配的方式真的是最小编辑距离。总之,绝大部分网上的答案都很轻视这种证明,似乎像在数学证明题中用“显然”,“不言自明”等方式来证明过程。当然啦,这是算法题,不是数学证明题,所以有很多时候,用不着那么严格,写出来的答案就是如此,也不好苛责别人。不过我想说的是,这种轻视最后一层证明的想法,对读者有害,因为会让你看完答案产生一种错觉,这题原来这么简单,然后下次做类似题目你依然不能很快冒出思路。

 

我这里做一个简要分析:如果细细考虑一点,会发现这种编辑距离的若干操作,从评估次数的角度,顺序不重要,例如从execution通过两次变换(先删掉x,再替换第一个e成为a)成为aecution,至于是先删x还是先换e,这根本不重要,得到的结果都一样,过程也都是两次。既然如此,我们就可以人为确定一种顺序来操作,因为任意一种顺序,都具有该操作次数的代表性。也就是说顺序不重要恰恰是一种福利让你利用任意的顺序(包括一种算起来方便的顺序),这就是为什么上面提到的网上的一些解法是可行的。。。以这样的视角来看我们做规模降级就更轻松一点了,没有那么大的变数了(不用再考虑随意位置的变动了)

 

降级的具体方法如下:

如果最后一个字符已经相等,则问题自动dp(M,N)降级为dp(M-1,N-1),

否则,

分别考虑三种情况让最后一个字符串相等,相等后问题就从dp(M,N)降级为dp(M-?,N-?)(这里为什么我用?代替看下面的论证),因为最后一个字符串已经相等了,就可以一起把这个相等的字符给删了,继续比前面的部分, 所以dp(M,N)同dp(M-?,N-?)的关系则分别从三种情况来推导:

1,插入的情况,则对应dp(M,N)=1+dp(M,N-1)

2,删除的情况则对应dp(M,N)=1+dp(M-1,N)

3,替换的情况对应dp(M,N)=1+dp(M-1,N-1),

那么三种情况取最小值即可, 也就是:

dp(M,N)=min{1+dp(M-1,N),1+dp(M,N-1),1+dp(M-1,N-1)},

以上三种情况插入和替换都比较好理解,插入就是插入一个一样的字符,替换就是把原字符替换成目标字符,唯独删除有点不好理解,难道我删了该字符,顶上来的字符就自动匹配上了?细想一下,如果你从子问题已经得到解决的情况下来看,答案是肯定的,我们动态规划就是从小的子问题扩张到大的原问题这样递推的,所以当你考虑N规模的时候,N-1规模的子问题应该已经默认完成了。

递推公式出来后,问题已经解决了一大半,不过不要得意,最后一步也得认真对待——找到基础case。为了尽可能符合直觉我们把M和N视为数组的下标,也就是通常编程语言从0开始的那个东西,那么在逐渐计算的过程中,M和N都会减小,为了表示整个串都已经匹配完毕的情况,我们还增加一个值为-1,代表当前串已经扫描匹配完了,如下几种情况:

1, M和N都为0了,这时看二者是否相等即可,如相等,则编辑距离为0,否则为1

2,M或N任意一个退得比较快,率先达到-1,那么另一方对应的index+1就代表了剩下这部分的编辑距离,对应全删或者全插入的操作

以上就是base case的设定。

 

有了递推公式和base case,基本上可以说已经完成了99%的工作了,

 

可是为了提高效率,还差一步,就像我们算fibbonaci数列一样,可能存在大量重复子问题,可别忽视这个问题,因为搞不好带来的计算量就是指数爆炸级,这里的问题显然也包含了重复子问题,所以最后还应该用memtable的方式来排除重复计算,这个就不细说了!

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值