一、概论
- 算法是一系列解决问题的明确指令
算法的特点
- 输入:>=0
- 输出:>=1
- 确定性
- 有限性
- 可行性
二、算法效率分析
2.1算法分析框架
- 运行时间
- 输入规模
- 算法的效率函数
- 最好情况、最坏情况、平均情况
- 平均复杂度
2.2 三种渐进符号
- O(g(n)):增长的比g(n)慢(或等于)
- n ∈ O(n2)
- Ω(g(n)):增长的比g(n)快(或等于)
- n3 ∈ Ω(n2)
2.3 非递归算法的效率
- 决定用哪个参数表示输入规模
- 找出算法的基本操作
- 检查基本操作的的执行效率是否只依赖于输入规模。
- 建立一个算法基本操作执行次数的求和表达式
- 用求和运算的标准公式和法则建立一个操作次数的闭合公式,或至少确定其增长次数
2.4 递归算法的效率
- 确定用哪个参数作为输入规模的度量标准
- 找出算法的基本操作
- 检查对相同规模的不同输入,基本操作的执行次数是否可能不同。如果可能,则最好情况、最坏情况和平均情况要分开讨论
- 对算法基本操作的执行次数建立一个递推关系及初始条件
- 解递推公式,或至少确定其增长次数
三、蛮力法
3.1 选择排序
3.2 冒泡排序
3.3 穷举法
旅行商问题(TSP)
- 问题:找出一条n个给定城市间的最短路径,使我们在回到出发点的城市之前,对每个城市都只访问一次
- 实质上是求图的最短哈密顿回路的问题
背包问题
- 给定n个重量为w1,w2…,wn,价值为v1,v2…,vn的物品和一个承重为W的背包,求这些物品中一个最有价值的子集,且能装入背包中
分配问题
- n个任务分给n个人,一个任务对应一个人,将第j个任务分配给第i个人的成本是C[i,j],求总成本最小的分配方案
四、递归算法
- 减常数因子
- T(n) = T(n-1) + f(n)
- T(n) = aT(n/b) + f(n)
五、分治法
- 将一个问题划分为同一类型的若干子问题
- 对子问题求解(递归)
- 有必要的话,合并子问题的解,得到原答案的解
- 通用分治递推式:T(n) = aT(n/b) + f(n)
5.1 大整数相乘
- 问题:两个n位的大整数相乘
5.2 Stranssen矩阵乘法
5.3 二分搜索
5.4 归并排序
5.5 快速排序
5.6 棋盘格问题
六、减治法
6.1 减去一个常量
插入排序
- 最坏:θ(n2)
- 最好:θ(n)
- 平均:θ(n2)
拓扑排序
- 执行一次DFS,并记住顶点退出栈的顺序,该顺序反过来就是拓扑排序的一个解
- 减治法:不断取出源(没有输入边的顶点)
6.2 减去一个常量因子
二分查找
- 时间复杂度:logn
假币问题
- 问题:在n个钱币中找出一个假币
- 思路:不断分为两堆进行称重(同二分查找)
俄罗斯农民问题
- 问题:计算n*m
6.3 减去的规模是可变的
七、变治法
7.1 实例化简
预排序
- 寻找唯一的元素
- 找mode(出现次数最多)
高斯消去法
堆排序
7.2 改变表现
霍纳法则
7.3 问题化简
线性规划
简化为图
八、回溯法和分支限界法
8.1 DFS
8.2 BFS
8.3 回溯法
0-1背包问题
TSP问题
n皇后问题
8.4 分支限界法
0-1背包问题
装载问题
8.5 方法比较
九、动态规划
- Bellman原理(最优性原理):求解问题的一个最优策略序列的子策略序列总是最优的
例:
- Fibinacci
- 两个重要的适用性质:最优子结构、重叠子问题
9.1 计算二项式系数
9.2 最长公共子序列(LCS)
9.3 动态矩阵相乘
9.4 0-1背包问题
9.5 多阶段决策问题
Forward
Backward
Warshall(求传递闭包)
Floyd(求最短路径)
9.6 最优性原理的证明
十、贪心技术
- 思想:一步步的局部最佳策略可能导致一个最优的结果
10.1 活动安排问题
10.2 背包问题
10.3 Dijstra算法
10.4 Prim算法
- 最小生成树:将所有顶点都连起来,且边的权重最小
- Prim:当需要新加节点时,选择最短的边加入
10.5 Kruskal算法
- 将所有边按权重由小到大排序,每次选最小的边,直到所有的顶点都被连起来