近日复习了一些算法知识,小记于此
- 递归与分治法
直接或间接地调用自身的算法称为递归算法。 递归是算法设计与分析中常用的一种技术,描述简单且易于理解。
分治法的设计思想是将一个规模为n难以解决的问题分解为k个规模较小的子问题,这些子问题
相互独立且
与原问题相同。 递归地解这些子问题,然后将各子问题的解合并得到原问题的解。
典型例子:Fibonacci数列,阶乘,Hanoi塔;
二分法搜索、快速排序、合并排序。
- 动态规划法
动态规划过程是:根据当前(阶段)状态,采取相应的决策,引起状态的转移。如下图,一个决策序列就是在变化的状态中产生出来的,这种多阶段最优化决策解决问题的过程就称为动态规划。
初始状态→│决策1│→│决策2│→…→│决策n│→结束状态
图1 动态规划决策过程示意图
动态规划过程中的转移中的状态可以是一个,也可以是一个集合,比如状态集合包含{a,b,c},但每一步的状态都是由上一步或几步的状态决定的。
动态规划算法与分治法类似,其思想也是将待求解问题分解成若干个子问题(一般每个问题对应一个阶段),
按顺序求解子阶段,前一子问题的解,为后一子问题的求解提供了有用的信息。在求解任一子问题时,列出各种可能的局部解,通过决策保留那些有可能达到最优的局部解,丢弃其他局部解。依次解决各子问题,最后一个子问题就是初始问题的解。
由于动态规划解决的问题多数有重叠子问题这个特点,为减少重复计算,对每一个子问题只解一次,将其不同阶段的不同状态保存在一个二维数组中。
与分治法最大的差别是:适合于用动态规划法求解的问题,经分解后得到的子问题往往不是互相独立的(即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解)。
典型例子:最长公共子序列; 最大连续子序列和(
最大m子段和)。
- 贪心算法
贪心算法在策略的执行过程中,总是做出对当前看来是最好的选择。也就是说贪心算法并不从整理最优上进行考虑,它所做出的选择只是在某种意义上的局部最优选择。
贪心算法不能保证找到的解是最优解,但在某些情况下可以是最优解的近似解,甚至是最优解。
典型例子:哈夫曼编码;单源最短路径(Dijkstra算法);最小生成树(Prim和Kruskal算法)
- 回溯法 (DFS搜索解空间)
回溯法是以深度优先方式搜索问题解的算法,它适用于组合数较大的问题,能系统地搜索到一个问题的所有解惑任一解。
回溯法解题通常包含3个步骤:①针对所给的问题,定义问题的解空间; ②确定易于搜索的解空间的结构; ③ 以DFS搜索解空间,并在搜索过程中用剪枝函数(约束条件)避免无效搜索。
解空间树:
①子集树:当所给问题是从n个元素的结合S中找出满足某种性质的子集时,相应的解空间树称为子集树。例如n个物品的0-1背包问题。这类子集树通常有2^n个叶节点,其节点总个数为为2^(n+1)-1。遍历子集树的任何算法均需O(2^n)的计算时间
②排列树:当所给问题是确定n个元素满足某种性质的排列时,相应的解空间树成为排列树。例如旅行售货员问题。排列树通常有n!个叶节点,因此遍历排列树需要O(n!)的计算时间。
搜索实现可以递归,也可以用树的非递归深度优先遍历算法来实现(用到
栈Stack)。
典型例子:八皇后(找出所有的解),
N 皇后
- 分支界限法(BFS搜索解空间)
分支界限法的求解目标是找出满足约束条件的一个解,或是在满足约束条件的解中找出使某一目标函数值达到极大或极小的解,即在某种意义下的最优解。(分支界限法与回溯法求解目标不同)
分支界限法以广度优先或以最小耗费(最大收益)优先的方式搜索解空间。所谓“分支”就是在扩展节点处,先生成其所有儿子节点(分支),然后在从当前的活结点表中选择下一个扩展节点,继续搜索。过程中可以用约束条件,进行剪枝。 常见的扩展节点的常见方式:
先进先出FIFO队列 和
优先队列分支界限法。
典型例子:单源最短路径