递归算法:是指一种通过重复将问题分节为同类的子问题而解决问题的方法。它能解决的问题有①数据的定义是按递归定义的,如斐波拉契数;②问题解法按递归算法实现,如汉诺塔问题;③数据的结构形式是按递归定义的,如二叉树和广义表等。
递归算法的模板如下:
void 递归函数(参数)
{
if(结束条件) //达到了结束的条件,即可执行当前的函数体并返回结果
{
//做输出结果的功能,并结束运行
}
else //未达到结束条件
{
//执行当前的操作
//改变条件和参数,进行下次的操作
}
}
它的调用过程为:①计算参数值,将函数压栈;②执行递归函数;③满足结束条件,结束函数,返回上层函数;
递归算法最常用的一些地方举例:①全排列;②斐波拉契数;③阶乘;④汉诺塔;⑤排列组合;⑥归并排序。
注意:递归一般需要有边界条件、递归前进段、递归返回段,当不满足边界条件时,递归前进,满足时进行返回操作。
分治算法:是将一个规模为N的问题分解为K个规模较小的子问题,这些子问题相互独立且与原文太性质相同,所以求出子问题的解,就能得到原文太的解,是一种分目标完成的算法,简单的问题用二分法即可解决。
分治算法的模板如下:
type DaC(Partition)
{
if |Partition|≤n0
then return(this->Partition)
else
将Partition分解为较小的子问题 P1 ,P2 ,...,Pk
for i←1 to k
do yi ← DaC(Pi) // 递归解决Pi
T ← MERGE(y1,y2,...,yk) // 合并子问题
return(T)
}
它的解题步骤为:①分解:将要解决的问题分成若干同类子问题;②求解:当子问题够小时,用较简单的方法解决;③合并:按原问题的要求,将子问题的解逐层合并构成原问题的解;
分治算法常用场景:①求最值;②二分搜索;③快速排序;④堆排序;
注意:分治算法需要保证原问题可以分解,然后由终止条件,最后则是可以合并为原问题
贪心算法:指在对问题求解时,总是做出在当前来看是最好的选择,也就是说,不从整体最优上来考虑答案,而是从局部上获得某种意义上的最优解。
贪心算法的模板是:
从问题某一初始解出发;
while(能朝给定总目标前进一步)
{
利用可行的策略,求出一个局部最优解;
}
由所有局部最优解合成问题的一个可行解;
它的解题步骤为:①把求解问题分成若干子问题;②对每一个子问题求解,得到子问题的局部最优解;③把子问题对应的局部最优解合成原来的整个问题的一个近似最优解;
贪心算法常用场景:割绳子、钱币找零问题、最优装载问题、迪杰斯特拉算法、求最小生成树的Prim算法和Kruskal算法
注意:贪心算法不能保证一定求得的是最优解,一般是用来解决求最大或最小问题的,也只能确定某些问题的可行性范围
动态规划:是运筹学的一个分支,是求解决策过程最优化的过程,主要用于求解以时间划分阶段的动态过程的优化问题,但是一些与时间无关的静态规划(如线性规划、非线性规划),只要人为地引进时间因素,把它视为多阶段决策过程,也可以用动态规划方法方便地求解。
动态规划的模板是:
def dynamicPro(nums):
if not nums or not nums[0]:
return
m,n = len(nums), len(nums[0])
dp = [[0 for _ in range(m)] for _ in range(n)]
dp[0][0], dp[0][1] = x,y
for i in range(m):
for j in range(n):
dp[i][j] = max/min(
dp[i-1][j-1],dp[i-1][j],dp[i][j-1])
return dp[m-1][n-1]
它的解题步骤:①判断是否符合最优子结构性质。符合进入步骤2,否则不能用动态规划计算;②建立子问题的递归关系式;③依据递归关系式按顺序解决需要解决的子问题,并将结果存储(一般使用***数组);④依据存储的结果获取求解答案;
动态规划常用场景:最优子结构、重叠子问题、背包问题、最长公共子序列、最优二分检索树
注意:动态规划的问题必须满足最优化原理和无后效性;即最优化原理:一个最优化策略具有这样的性质,不论过去状态和决策如何,对前面的决策所形成的状态而言,余下的诸决策必须构成最优策略;无后效性:每个状态都是过去历史的一个完整总结。这就是无后向性,又称为无后效性
回溯算法:实际上是一个类似于枚举的搜索尝试过程,主要是在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就“回溯”返回,尝试别的路径。回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标。但当探索到某一步时,发现原先选择并不优或达不到目标,就退回一步重新选择,这种走不通就退回再走的技术为回溯法,而满足回溯条件的某个状态的点称为“回溯点”。
回溯算法的模板是:
begin
for i:=1 to 边界 Do {枚举所有方法}
begin
保存结果
if 达到目的 then 输出解结果
else Try(k+1);
恢复:保存结果之前的状态{回溯一步}
end;
end;
它的解题步骤为:①针对问题,定义问题的解空间,它至少包含一个最优解;②确定易于搜索的解空间结构,使得能用回溯法方便的搜索整个空间;③以深度优先的方式搜索解空间,并且在搜索过程中用剪枝函数避免无效搜索;
回溯算法常用场景为:八皇后问题、0-1背包问题、迷宫问题、寻找最优子集;
注意:需要考虑路径、选择列表和结束条件,路径:也就是已经做出的选择;选择列表:也就是你当前可以做的选择;结束条件:也就是到达决策树底层,无法再做选择的条件。