口诀
#
难题首选动归
受阻贪心暴力
考虑分治思想
配合排序哈希
递归(recursion)
#
介绍
利用递归,把状态的管理责任推给运行时
递归转迭代
可加上memory做优化
分治(divide and conquer)
#
介绍
广义分治法
例子
二分检索
找最大/最小元素
归并分类
快速分类
选择问题
斯特拉森矩阵乘法
贪心(greedy)
#
案例
Dijkstra最短路径
最小生成树Prim, Kruskal
背包问题
作业排序
最优归并模式
动态规划(dynamic planning)
#
方法
常用滚动数组降低空间复杂度
案例
多段图
结点间最短路径
最优二叉检索树
0/1背包问题
可靠性设计
货郎担问题(旅行商问题)
流水线调度问题
检索与周游(retrieval/travel)
#
案例
深度优先检索
广度优先检索
与/或图
对策树
回溯(backtracking)
#
案例
8皇后问题
图的着色
哈密顿环
背包问题
暴力(brute force)
#
介绍
分支限界条件加快效率
例子
DFS, BFS
- 分支-限界(branch and bound)
案例
LC检索
0/1背包问题
货郎担问题
并行(parallel)
#
时间复杂度(time complexity)
#
O()表示上界(<=), Ω() [omega]表示下界(>=), Θ() [Theta] 表示上下界相同, o()表示非Θ()的O()
N >= n0时, T(N) <= cf(N), 记为T(N) = O(f(N))
N >= n0时, T(N) >= cg(N), 记为T(N) = Ω(g(N))
T(N) = Θ(h(N)) 当且仅当T(N) = O(h(N)) 和 T(N) = Ω(h(N))
上界(upper bound)
下界(lower bound)
法则
# 约定, 不存在特定的时间单位
# 约定, 机器模型中, 1. 所有指令顺序执行。2. 任一简单的工作都恰好花费一个时间单位
## 假设不存在如矩阵求逆或排序这样的单位操作
1. 如果T1(N) = O(f(N)), T2(N) = O(g(N)), 那么
T1(N) + T2(N) = O(f(N) + g(N)), 或写成 max(O(f(N)), O(g(N)))
T1(N) * T2(N) = O(f(N) * g(N))
2. 如果T(N)是一个k次多项式, 则T(N) = Θ(N^k)
3. 对任意常数k, (logk) * N = O(N)
# 对数增长得非常缓慢
一般法则
1. for 循环时间, 为内部语句的运行时间 * 迭代次数
2. 嵌套for 循环, 内部语句时间 * 迭代次数n次方
3. 顺序语句, 各语句时间求和
4. if(S1)/else(S2), 判断的运行时间加 S1和S2中时间长者
相对增长率(relative rate of growth)
lim(N->∞)f(N)/g(N)来确定两个函数的相对增长率
1. 极限是0, 则f(N) = o(g(N))
2. 极限是c<>0, 则f(N) = Θ(g(N))
3. 极限是∞, 则g(N) = o(f(N))
4. 极限摆动,则f(N)与g(N)无关
洛必达法则
lim(N->∞)f(N) = ∞, 且lim(N->∞)g(N) = ∞ 时, lim(N->∞)f(N)/g(N) = lim(N->∞)f'(N)/g'(N)
多项式时间算法
O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3)
指数时间算法
O(2^n) < O(n!) < O(n^n)

递归分析
1. 如求factorial(阶乘)的简单for循环, 则为O(N)
2. 求解一个递推关系, 如fabonacii, return fib(n - 1) + fib(n - 2)
T(N) = T(N - 1) + T(N - 2) + 2, 又fib(N) = fib(N - 1) + fib(N - 2), 由归纳法得T(N) >= fib(N)
又fib(N) < (5/3)^N, 可知时间指数增长
# 该算法大量重复计算, 违反递归的合成效益法则
3. 对于T(N) = aT(N / b) + Θ(N^k), 解为
O(N^(log(b)(a))), 若 a > b^k
O(N^k * logN), 若 a = b^k
O(N^k), 若 a < b^k
影响性能的其它因素
程序实现方法和语言
数据读入
空间复杂度(space complexity)
#
Space(N) = Heap(N) + Stack(N), 忽略低次项、系数
# Heap表示额外申请堆内存空间大小, Stack表示函数栈的最大深度