目录
第一章 算法引言
什么是算法?
可由一个给定计算模型机械地执行的规则或计算步骤序列称为该计算模型的一个计算。
满足以下条件:
- 有穷性/终止性:有限步内必须停止,
- 确定性:每一步都是严格定义和确定的动作
- 能行性:每一个动作都能够被精确地机械执行
- 输入:有一个满足给定约束条件的输
- 输出:满足给定约束条件的结果
如果计算永远不停止,那么洲哥计算便不是算法
算法正确性证明
- 证明算法对所有输入都停止
- 证明对每个输入都产生正确结果
复杂度的定义:
时间复杂性:一个算法对特定输入的时间复杂性是该算法对该 输入产生结果需要的原子操作或“步”数
空间复杂性:一个算法对特定输入的空间复杂性是该算法对该 输入产生结果所需要的存储空间大小
伪代码书写的一些约定
- 第一行要写函数的名称,参数 比如:functionA(a,b,c):
- for循环格式:for 起始条件 to/downto 结束条件,如果循环每次加的不是1,便在后面加上 by x(x是每轮循环增加的数值),结束后循环计数器保持最终值
- if-else格式:可以省略if后面的关键词then,else的缩进与if相匹配
- 缩进表示块结构
- 可以使用多重赋值,比如i=j=k
- 如果无显示说明,不适用全局变量
考试考察了算法的正确性证明,这个地方还是需要👀👀(本来以为不会考的)
第二章 算法分析的数学基础
算法复杂度的分析的数学基础
渐进符号 | 含义 |
---|---|
Θ | 渐进紧确界 |
O | 渐进上界 |
Ω | 渐进下界 |
o | 非渐近紧确的上界 |
ω | 非渐近紧确的下界 |
书面定义的格式,取Θ为例:
Θ
(
g
(
n
)
)
Θ(g(n))
Θ(g(n))={
f
(
n
)
f(n)
f(n)|:存在正常量
c
1
,
c
2
,
n
0
c_1,c_2 ,n_0
c1,c2,n0,使得对所有的
n
≥
n
0
n \geq n_0
n≥n0,都有
0
≤
c
1
g
(
n
)
≤
f
(
n
)
≤
c
2
g
(
n
)
0\leq c_1g(n) \leq f(n) \leq c_2g(n)
0≤c1g(n)≤f(n)≤c2g(n) }
同样我们可以说:
f
(
n
)
f(n)
f(n)=
Θ
(
g
(
n
)
)
Θ(g(n))
Θ(g(n)),则存在正常量
c
1
,
c
2
,
n
0
c_1,c_2 ,n_0
c1,c2,n0,使得对所有的
n
≥
n
0
n \geq n_0
n≥n0,都有
0
≤
c
1
g
(
n
)
≤
f
(
n
)
≤
c
2
g
(
n
)
0\leq c_1g(n) \leq f(n) \leq c_2g(n)
0≤c1g(n)≤f(n)≤c2g(n)
其他几种符号同理
master定理
此章节还要一个重要内容就是master定理
求解方程: T ( n ) = a T ( n / b ) + f ( n ) T(n)=aT(n/b)+f(n) T(n)=aT(n/b)+f(n)要求 a ≥ 1 , b > 0 , f ( n ) 是 正 函 数 a\geq 1,b>0,f(n)是正函数 a≥1,b>0,f(n)是正函数
master定理主要就是比较 f ( n ) f(n) f(n)与 n l o g b a n^{log_{b}a} nlogba的阶数
条件 | 结果 |
---|---|
f ( n ) f(n) f(n)是 n l o g b a n^{log_{b}a} nlogba的高阶函数 | T ( n ) = Θ ( n l o g b a ) T(n)= Θ(n^{log_{b}a}) T(n)=Θ(nlogba) |
f ( n ) f(n) f(n)是 n l o g b a n^{log_{b}a} nlogba的同阶函数 | T ( n ) = Θ ( f ( n ) l o g ( n ) ) T(n)= Θ(f(n)log(n)) T(n)=Θ(f(n)log(n)) |
f ( n ) f(n) f(n)是 n l o g b a n^{log_{b}a} nlogba的低阶函数 | T ( n ) = Θ ( f ( n ) ) T(n)= Θ(f(n)) T(n)=Θ(f(n)) |
可以看出来的规律就是
T
(
n
)
T(n)
T(n) 总是取
f
(
n
)
f(n)
f(n)与
n
l
o
g
b
a
n^{log_{b}a}
nlogba中的最大者,如果两者相同,则取
T
(
n
)
=
Θ
(
f
(
n
)
l
o
g
(
n
)
)
T(n)= Θ(f(n)log(n))
T(n)=Θ(f(n)log(n))
第三章 分治法
分治法的时间复杂度一般可以总结为:
T
(
n
)
=
a
T
(
n
/
b
)
+
D
(
n
)
+
C
(
n
)
T(n)=aT(n/b)+D(n)+C(n)
T(n)=aT(n/b)+D(n)+C(n)
将每个问题划分为
a
a
a份,每份的独立解决代价为
n
/
b
n/b
n/b
其中
D
(
n
)
D(n)
D(n)是划分的代价,
C
(
n
)
C(n)
C(n)是合并的代价
第四章 动态规划
可以看这个博客算法设计之动态规划速通
第五章 贪心算法
可以看这个博客贪心算法
第六章 平摊分析
可以看这个博客平摊分析——一种特殊的分析方法
第七章 最大流与最小割
主要内容有FF算法,二分图的匹配
可以看这个博客最大流 Ford-Fulkerson 算法
FF算法的核心思想还是从任何一个可行流开始,沿增广路径对流进行增广,然后不断重复此过程,直到网络中不存在增广路径为止。
最大流最小割定理便是最大流==最小割
二分图的匹配主要讲二分图的最大匹配,就是存在的边数取最大值的情况
可以在两个划分左右分别添加源点和汇点,将每条边的流量视为1,然后就转化为了一个求最大流的问题
第八章 搜索
这章节讲了很多基于图的搜索
比如基础的
-
DFS
-
BFS
和图搜索的优化策略 -
爬山法 :就是局部贪心,每次选择总选择最优的
-
Best-first策略:对整体的成本进行估测,选择成本最低的节点作为下一个要扩展的节点
-
分支预测(剪支法):剪除那些不可能产生最优解的分支
-
A*算法 核心是告诉我们在某些情况下, 我们得到的解一定是优化解, 于是算法可以停止,试图尽早地发现优化解 ,常使用Best-first策略求解优化问题,如果解存在,A*算法保证找到的最优解
博客: A*算法与搜索
第九章 字符串
这章节主要讲了三个算法:
- 基于指纹的算法:Hash函数生成指纹
- KMP算法:预处理生成一个表,每当匹配失败查表,尽可能利用之间已经匹配的位 ,复杂度O(m+n)
- BHM算法:从模式的最后一位开始匹配
和三个数据结构
- 前缀树 Trie(字典树):就是根据前缀生成一棵树,利用了单词之间共享前缀的特点
- Patricia Trie :一种紧缩 trie 其中每个边的标记的树,如果一颗Trie中有很多单词只有一个儿子结点,可以用Patricia Trie来压缩存储
- 后缀树:包含文本所有后缀的紧缩trie树,例如:carrara
附录 经典算法总结
https://blog.csdn.net/Franklins_Fan/article/details/107533813
0-1背包
完全背包
最长公共子序列
任务安排问题(贪心法)
最小生成树算法
- Kruskal
- Prim
单源最短路径算法
- dijkstra
- Floyd