1、算法与问题
算法求解基本步骤:
1.理解问题:最基础也是重要的一步,决定着算法的成败
2.了解计算设备的性能:根据不同计算设备的性能往往需要不同的算法策略(顺序算法、并行算法)
3.在精确解法和近似解间做选择:对于一些无法在目前或者在时间限制内找到精确解法的问题,我们就必须在两者之间做出选择
4.确定适当的数据结构:我们都知道程序=算法+数据结构
5.选择恰当的算法:即根据问题和数据结构本身选择恰当的算法,可以是成熟的,也可以是自己开创的
6.详细的表述算法:伪代码是一个不错的选择
7.证明算法的正确性:不光是算法本身的正确性,还必须有“有限时间内”这个条件限制
8.分析算法:时间效率、空间效率角度去研究和分析改进算法
9.实现算法并调试
解决问题的时候可以首先考虑蛮力法,因为蛮力法一般都能解决,只是效率比较低。使用蛮力法解决问题之后可以再考虑使用其他算法思想进行优化。在使用蛮力法的时候如果解决起来比较费力,可以再次思考一下问题,看看能不能找到什么规律,然后,在该规律之上再求解。
蛮力法往往需要从头到尾遍历所有的可能,而且有时候一个问题可能会有好几种遍历策略,有的策略能够得到问题的解,有一些不能导出最终问题的解,所以,使用蛮力法的时候遍历策略的选择往往是很重要的。好的遍历策略甚至能起到跟贪婪,动态规划策略一样的作用,从这个意义上来说贪婪,动态规划,回溯,分支界限也算是一种蛮力法,只不过是聪明的蛮力法。
优化的思路有以下3个方向:
1、蛮力法—>贪婪,动态规划—>回溯,分支界限
2、分治,减治,变治
3、时空权衡
2、蛮力法
蛮力法是一种简单直观的解决问题的办法,常常直接基于问题的描述和所涉及的概念。蛮力法所能解决的问题域也是最广的,但是效率往往不高;
使用蛮力法的算法有:
1、冒泡排序,选择排序
2,、顺序匹配
3、穷举法
3、分治法
分治法设计步骤:
1、将问题实例划分为同一问题的较小的实例,最好拥有同样的规模;
2、求解较小的实例;
3、合并较小问题的解;
分治法算法:
1、归并排序,快速排序
2、折半查找
3、二叉树遍历(前序,中序,后序)
4、大整数乘法和矩阵乘法的分治
5、最近对和凸包问题的分治
4、减治法
减治技术应用了问题的解和同样问题较小实例的解之间的关系,减治法主要有一下三种:
1、减去一个常量 每次减去一个规模相同的常量,一般等于1或者2,例如求a的n次方可以理解为f(n)=f(n-1)*a
2、减去一个常量因子 每次迭代减去相同的常数因子,例如每次把问题规模变为原来问题的1/2,还是求a的n次方
3、减去的规模是可变的 每次迭代减去的问题规模是可变的,例如求最大公约数 gcd(m,n) = gcd(n,m mod n),还有基于快速排序查找第k大的数;
减治法算法(减常量):
插入排序、深度优先查找、广度优先查找、拓补排序、生成排列组合、生成子集
减常因子算法:
假币问题、约舍夫斯问题
减可变规模
基于快速排序查找第k大的数、插值查找、二叉查找树的插入和查找
5、动态规划
动态规划的出现是用来解决交叠子问题的重复求解问题,具体的求解过程一般分以下两步:
1、确定递推关系
2、根据问题性质采取合适的规划策略,自底向上递推或是自顶向下记忆化搜索
记忆化搜索也要维护一张状态表格,但每次要计算新值的时候会先查找表格该值是否计算过,如果已经计算过就直接用,否则递归计算。
动态规划算法:
1、计算二项系数
C(n,k) = C(n-1,k-1)+C(n-2,k)
2、Warshall算法计算传递闭包
3、Floyd算法计算完全最短路径
4、最优二叉树构造
5、背包
6、贪心
贪心算法:
1、Prim,Kruskal算法求最小生成树
2、Dijkstra算法
3、Huffman
7、迭代改进
从某些可行解出发,然后重复应用一些简单的步骤不断改进它:
1、构造可行解;
2、检查当前解是不是最优的,如果不是,替换它;
迭代改进算法:
1、单纯形法与线性规划
2、最大流
3、递归下降
4、稳定婚姻
5、EM
6、二分图匹配