随便取一个代表类型的题目,其实也就是求从字符串a变形到字符串b,需要多少次操作。
直接上思路:
我们可以按照从后往前遍历的顺序,判断a[i]===b[j]?,如果为真,则i-1,j-1,执行skip操作,直接看前面一个:
为假,需要判断3个操作(假定为从b变到a,但其实无论从谁变到谁,结果都一样)
- 插入(在b[j]的位置插入一个与a[i]一样的字母,因为b的长度变长了,所以其实就是i–,j不变)《按照尾插》
- 删除(删除b[j]这个元素,那么i不变,j–)《因为此时还不满足a[i]===b[j],所以j还需要往前》
- 替换(替换掉,则a[i]===b[j]了,所以i–,j–)
但是呢,由于3个操作都是可以执行的,那么其实我们就需要列出所有操作的组合了,这个最经典的解法就是递归了。既然要递归,那么一定要有个出口,
这个出口其实就是咱们没考虑的a和b的长度差异了,假设a先遍历完,那么此时的结果就是abc和ffabc了,注意,此时两者后面为a长度的子字符串一定是相等了的,也就是b的前两个元素还没遍历到,这个时候,肯定是要加上剩下的2个操作的,无论是add还是remove,都一定需要2个操作了。反之,b先遍历完也是如此,所以我们最后的操作数就要加上剩下的j或者是i
注意,最后之所以返回j+1或者i+1,是因为咱们索引是以0为起点的,因此按照上面的例子,剩下的是b[0]和b[1],j是为1的,所以还要加上1。
But,我们之前说过,递归就是把所有可能的操作组合列出来,约等于暴力解法,中间存在太多重复子路径了,因此我们需要进行优化,要优化,就要用动态规划!
其实不难想到,我们每一次的操作都是可以基于上一次的最优解的操作数上执行的,思路和递归的基本一致
我们此时的base(出口),就是第0列和第0行了,上个图
应该非常容易理解了吧。。。。。