前言
递归是一种编程技巧,一种解决问题的思维方式;
其他的思想都是基于递归的!
分治算法和动态规划很大程度上是递归思想基础上的(虽然动态规划的最终版本大都形式上不是递归了,但解题思想离不开递归)解决更具体问题的两类算法思想;
贪心算法是动态规划算法的一个子集,可以更高效解决一部分更特殊的问题。
一、动态规划和递归(回溯,分治)
递归和动态规划是从保存过程信息角度划分的。
-
递归:
做为一种算法在程序设计语言中广泛应用。 一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。 -
动态规划:
动态规划其实和分治策略是类似的,也是将一个原问题分解为若干个规模较小的子问题,递归的求解这些子问题,然后合并子问题的解得到原问题的解。 -
区别:
区别在于这些子问题会有重叠,一个子问题在求解后,可能会再次求解,于是我们想到将这些子问题的解存储起来,当下次再次求解这个子问题时,直接拿过来就是。
其实就是说,动态规划所解决的问题是分治策略所解决问题的一个子集,只是这个子集更适合用动态规划来解决从而得到更小的运行时间。即用动态规划能解决的问题分治策略肯定能解决,只是运行时间长了。
二、贪心算法和动态规划
贪心和动态规划是从全局最优角度划分的:
能从局部最优推导出全局最优就是贪心,否则就是动态规划。
-
贪心算法:
贪心算法中,作出的每步贪心决策都无法改变,因为贪心策略是由上一步的最优解推导下一步的最优解,而上一部之前的最优解则不作保留。 -
联系:
动态规划和贪心算法都是一种递推算法。
均由局部最优解来推导全局最优解。 -
区别:
1.全局最优解中一定包含某个局部最优解,但不一定包含前一个局部最优解,因此需要记录之前的所有最优解
2.动态规划的关键是状态转移方程,即如何由以求出的局部最优解来推导全局最优解
3.边界条件:即最简单的,可以直接得出的局部最优解
三、回溯算法和分治算法
回溯与其他递归算法是从剪枝角度划分的
-
分治策略:
将原问题分解为若干个规模较小但类似于原问题的子问题,递归的求解这些子问题,然后再合并这些子问题的解来建立原问题的解。
因为在求解大问题时,需要递归的求小问题,因此一般用递归的方法实现,即自顶向下(下面解释)。 -
回溯算法
回溯算法实际上一个类似枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。
回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法。 -
分治与回溯的区别:
递归是一种算法结构。递归会出现在子程序中,形式上表现为直接或间接的自己调用自己。典型的例子是阶乘,计算规律为:n!=n×(n−1)!,如果用 C++ 代码表示,基本如下所示。回溯是一种算法思想,它是用递归实现的。回溯的过程类似于穷举法,但回溯有“剪枝”功能,即自我判断过程。例如有求和问题,给定有 7 个元素的组合 [1, 2, 3, 4, 5, 6, 7],求加和为 7 的子集。累加计算中,选择 1+2+3+4 时,判断得到结果为 10 大于 7,那么后面的 5, 6, 7 就没有必要计算了。这种方法属于搜索过程中的优化,即“剪枝”功能。
int fac(int n) {
if(n == 1) return n;
else
return (n*fac(n - 1));
}