在很多算法书中都是把贪婪选择即贪心算法排在第一个讲述,继而再讨论分治策略和动态规划。其实,分治策略才是最基础的,动态规划、贪婪选择可以说是建立在其基础上的(算法导论中就按照分治策略、动态规划、贪婪选择的顺序来讲的)。那分之策略、动态规划、贪婪选择以及递归之间到底有啥联系与区别呢?
1、分治策略(Divide and Conquer)
将原问题分解为若干个规模较小但类似于原问题的子问题(Divide),递归的求解这些子问题(Conquer),然后再合并这些子问题的解来建立原问题的解。因为在求解大问题时,需要递归的求小问题,因此一般用递归的思想实现,即自顶向下。
2、动态规划(Dynamic Programming)
动态规划其实和分治策略是类似的,也是将一个原问题分解为若干个规模较小的子问题,递归的求解这些子问题,然后合并子问题的解得到原问题的解。区别在于这些子问题会有重叠,一个子问题在求解后,可能会再次求解,于是我们想到将这些子问题的解存储起来,当下次再次求解这个子问题时,直接拿过来就是。其实就是说,动态规划所解决的问题是分之策略所解决问题的一个子集,只是这个子集更适合用动态规划来解决从而得到更小的运行时间。即用动态规划能解决的问题分治策略肯定能解决,只是运行时间长了。因此,分治策略一般用来解决子问题相互对立的问题,称为标准分治,而动态规划用来解决子问题重叠的问题。
动态规划一般由两种方法来实现,一种为自顶向下的备忘录方式,用递归实现,一种为自底向上的方式,用迭代实现。下一文中会详细介绍。
3、贪心选择(Greedy Algorithm)
贪心算法在每一步都做出局部最优的选择,寄希望这样的选择能导致全局最优解。对,只是寄希望,因此贪心算法并不保证得到最优解,但是它对很多问题确实可以得到最优解,而且运行时间更短。那什么时候可以用贪心算法呢?当该问题具有贪心选择性质的时候,我们就可以用贪心算法来解决该问题。
贪心选择性质:我们可以通过做出局部最优(贪心)来构造全局最优。只要我们能够证明该问题具有贪心选择性质,就可以用贪心算法对其求解。比如对于0-1背包问题,我们用贪心算法可能得不到最优解(当然,也可能会得到最优解),但对于部分背包问题,则可以得到最优解,贪心算法可以作为0-1背包问题的一个近似算法。
4、总结
分治策略一般用于解决子问题相互独立的情况,一般用递归实现;而动态规划则用户解决子问题有重叠的情况,既可以用递归实现,也可以用迭代实现,贪心选择则用户解决具有贪心选择性质的一类问题,既可以用递归实现,也可以用迭代实现,因为很多递归贪心算法都是尾递归,很容易改成迭代贪心算法。