1. 分治思想
例题:分析归并排序的时间复杂度。
考点:分治法以及分治法时间复杂度的计算推导公式。
归并排序是一种基于分治思想的排序算法,分治思想是将一个大问题分割成许多小问题,这些小问题相互独立且与原问题相同,递归解决小问题后再将他们合并在一起。
归并排序的基本思想如下:
分割:将待排序的数组递归地分割成两个子数组,直到每个子数组只包含一个元素。这个过程的时间复杂度为
O
(
l
o
g
n
)
O(logn)
O(logn),其中
n
n
n是待排序数组的长度。
合并:将两个有序子数组合并成一个更大的有序数组,重复这个过程直到整个数组有序。合并的过程需要将两个有序子数组合并成一个有序数组,合并的时间复杂度与待排序数组的大小成线性关系,即
O
(
n
)
O(n)
O(n)。因为在合并过程中,需要比较和移动每个元素,而数组的大小为
n
n
n。
因此归并排序的时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)。
下面从分治法的递归方程出发,来计算其时间复杂度:
T
(
n
)
=
{
O
(
1
)
n
=
1
k
T
(
n
/
m
)
+
f
(
n
)
n
>
1
T(n)=\left\{ \begin{aligned} &O(1) & n=1\\ &kT(n/m)+f(n) &n>1\\ \end{aligned} \right.
T(n)={O(1)kT(n/m)+f(n)n=1n>1
其中
k
k
k是子问题的个数,
n
n
n是原问题的规模,
n
/
m
n/m
n/m是子问题的规模,
f
(
n
)
f(n)
f(n)是合并所需要的时间。
在归并算法中,
k
=
2
,
m
=
2
,
f
(
n
)
=
O
(
n
)
k=2,m=2,f(n)=O(n)
k=2,m=2,f(n)=O(n)
先推导一般公式,然后我们再代入计算,当
n
>
1
n>1
n>1时:
T
(
n
)
=
k
T
(
n
/
m
)
+
f
(
n
)
=
k
[
k
T
(
n
/
m
2
)
+
f
(
n
/
m
)
)
]
+
f
(
n
)
=
k
[
k
[
k
T
(
n
/
m
3
)
+
f
(
n
/
m
2
)
]
+
f
(
n
/
m
)
]
+
f
(
n
)
=
k
3
T
(
n
/
m
3
)
+
k
2
f
(
n
/
m
2
)
+
k
f
(
n
/
m
)
+
f
(
n
)
.
.
.
.
.
继续向下推导可得,当
n
/
m
w
=
1
时,即
w
=
l
o
g
m
n
,有
=
k
l
o
g
m
n
+
∑
j
=
0
l
o
g
m
n
−
1
k
j
f
(
n
/
m
j
)
由换底公式可得
=
n
l
o
g
m
k
+
∑
j
=
0
l
o
g
m
n
−
1
k
j
f
(
n
/
m
j
)
\begin{aligned} T(n) & = kT(n/m)+f(n) \\ & = k[kT(n/m^2)+f(n/m))]+f(n)\\ & = k[k[kT(n/m^3)+f(n/m^2)]+f(n/m)]+f(n) \\ & = k^3T(n/m^3)+k^2f(n/m^2)+kf(n/m)+f(n) \\ &.....\text{继续向下推导可得,当}n/m^w=1时,即w={log_mn},有\\ & = k^{log_mn}+\sum_{j=0}^{log_m{n}-1} k^jf(n/m^j)\\ & \text{由换底公式可得}\\ & = n^{log_mk}+\sum_{j=0}^{log_m{n}-1} k^jf(n/m^j)\\ \end{aligned}
T(n)=kT(n/m)+f(n)=k[kT(n/m2)+f(n/m))]+f(n)=k[k[kT(n/m3)+f(n/m2)]+f(n/m)]+f(n)=k3T(n/m3)+k2f(n/m2)+kf(n/m)+f(n).....继续向下推导可得,当n/mw=1时,即w=logmn,有=klogmn+j=0∑logmn−1kjf(n/mj)由换底公式可得=nlogmk+j=0∑logmn−1kjf(n/mj)
将
k
=
2
,
m
=
2
,
f
(
n
)
=
O
(
n
)
k=2,m=2,f(n)=O(n)
k=2,m=2,f(n)=O(n)带入得
T
(
n
)
=
n
l
o
g
2
2
+
∑
j
=
0
l
o
g
2
n
−
1
2
j
f
(
n
/
2
j
)
=
n
+
n
l
o
g
2
n
\begin{aligned} T(n)&=n^{log_22}+\sum_{j=0}^{log_2{n}-1} 2^jf(n/2^j)\\ &=n+nlog_2n \end{aligned}
T(n)=nlog22+j=0∑log2n−12jf(n/2j)=n+nlog2n
因此归并排序的时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)。
汉诺塔:
二分搜索:
典型的二分搜索的递推公式:
T(n) = T(n/2) + O(1)
2.动态规划
例题1:找出序列 (A, B, C, B, D) 与 (A, C, B, D) 的最长公共子序列,同时给出程序运行中间结果的两个矩阵
子序列定义:一个给定序列的子序列是在该序列中删去若干元素后得到的序列。
该题中最长公共子序列是(A, C, B, D)
令
c
[
i
]
[
j
]
c[i][j]
c[i][j]记录
X
i
和
Y
j
X_i和Y_j
Xi和Yj的最长公共子序列,则有:
c
[
i
]
[
j
]
=
{
0
i
=
0
,
j
=
0
c
[
i
−
1
]
[
j
−
1
]
+
1
x
i
=
y
j
m
a
x
{
c
[
i
]
[
j
−
1
]
,
c
[
i
−
1
]
[
j
]
}
x
i
≠
y
j
c[i][j]=\left\{ \begin{aligned} &0 & i=0,j=0\\ &c[i-1][j-1]+1 &x_i=y_j\\ &max\{c[i][j-1],c[i-1][j]\} &x_i\neq y_j\\ \end{aligned} \right.
c[i][j]=⎩
⎨
⎧0c[i−1][j−1]+1max{c[i][j−1],c[i−1][j]}i=0,j=0xi=yjxi=yj
第一个矩阵记录上方的
c
[
i
]
[
[
j
]
c[i][[j]
c[i][[j]:
第二个矩阵记录第一个矩阵对应元素来自哪里,当然这个并不唯一。(我这里是记来自斜上方为1,来自上方为2,左方为3):
例题二:矩阵维度存储于向量 p = [20, 15, 5, 30, 20],给出最优加括号方式,以及程序运行中间结果的两个矩阵(矩阵连乘算法)
基本认识:一个
m
×
n
m\times n
m×n的矩阵和
n
×
k
n\times k
n×k的矩阵相乘,要做m*n*k次乘法。计算的方式是沿着对角线进行计算
这里给定了四个矩阵,分别是
A
1
=
20
×
15
,
A
2
=
15
×
5
,
A
3
=
5
×
30
,
A
4
=
30
×
20
A1=20\times 15,A2=15\times 5,A3=5\times 30,A4=30\times 20
A1=20×15,A2=15×5,A3=5×30,A4=30×20
计算逻辑如下。沿对角线方向计算(括号内为新矩阵大小):
举例:如
A
1
A
2
=
20
×
15
×
5
=
1500
,
A
2
A
3
=
15
×
5
∗
30
=
2250
,
(
A
1
A
2
)
A
3
=
A
1
A
2
+
20
∗
5
∗
30
=
4500
,
A
1
(
A
2
A
3
)
=
A
2
A
3
+
20
∗
15
∗
30
=
11250
\\ A1A2=20×15×5=1500,\\A2A3=15×5*30=2250, \\(A1A2)A3 = A1A2+20*5*30=4500,\\A1(A2A3)=A2A3+20*15*30=11250
A1A2=20×15×5=1500,A2A3=15×5∗30=2250,(A1A2)A3=A1A2+20∗5∗30=4500,A1(A2A3)=A2A3+20∗15∗30=11250
得到的矩阵一为结果矩阵:
矩阵二记录的加括号的位置:
最后的结果为(A1A2)(A3A4)
3.贪心算法正确性证明
从两个方面出发,一是贪心策略的证明,二是最优子结构的证明。
贪心策略的核心思想是在每一步选择中,都选取当前状态下最好或者最优(最有利)的选择,从而希望导致结果是最好或最优的。
最优子结构:当问题的最优解包含了其子问题的最优解时,称该问题具有最优子结构性质。
这里有5个例题:
例题1. 证明Dijkstra算法的正确性
例题2. 证明Prim算法的正确性
prim:
(1)初始化:从图中任选一顶点,作为第一个顶点加入到最小生成树中;
(2)循环:从剩余的顶点中,找到最小代价的边,将这条边加入到最小生成树中,并将这条边的顶点也加入到最小生成树中;
(3)重复:重复步骤2,直到最小生成树中包括全部的顶点;
(4)停止:最小生成树已经构造完成,停止算法的执行。
例题3. 证明Kruskal算法的正确性
例题4. 证明活动安排问题算法的正确性
例题5. 证明哈夫曼编码算法的正确性
4.考查各算法的具体使用方式(上面的问题)
例题:已知字符 a – g 的权重依次是 12, 3, 20, 30, 18, 2, 15. 画出 Huffman 树,并计算平均编码长度
(考查哈夫曼树的知识)
哈夫曼树:给定n个权值作为n个叶子结点,构造一棵二叉树,若该树的带权路径长度达到最小,称这样的二叉树为最优二叉树,也称为哈夫曼树,可以说,哈夫曼树是一种特殊的二叉树,这种树的所有的叶子结点都有权值,从而构造出带权路径长度最短的二叉树,其中权值较大的结点离根较近。
平均编码长度的计算方式为:各个符号出现的概率乘以它的编码长度。
案例
第一步:按权值排序f:0.02,b:0.03,a:0.12,g:0.15,e:0.18,c:0.20,d:0.30,将最小的两个组合:
将组合之后得到的树继续放入其中,进行排序,再将最小的两个组合,一直到仅剩一个数
得到的结果为:
平均编码长度:
2 ∗ 0.18 + 2 ∗ 0.20 + 2 ∗ 0.3 + 3 ∗ 0.15 + 4 ∗ 0.12 + 5 ∗ 0.02 + 5 ∗ 0.03 = 2.54 2*0.18+2*0.20+2*0.3+3*0.15+4*0.12+5*0.02+5*0.03=2.54 2∗0.18+2∗0.20+2∗0.3+3∗0.15+4∗0.12+5∗0.02+5∗0.03=2.54
5.回溯算法
例题1:给出 5 皇后问题的前2个解
n皇后问题是不能横着、竖着和斜对角线相连。
1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|
1 | 1 | ||||
2 | 1 | ||||
3 | 1 | ||||
4 | 1 | ||||
5 | 1 |
1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|
1 | 1 | ||||
2 | 1 | ||||
3 | 1 | ||||
4 | 1 | ||||
5 | 1 |
例题2:根据如下地图,画出相应的平面图(即不要出现线的交叉),并给出着4种颜色的前 3 种方案(图的m着色问题:四色猜想)
将它用网状图表示出来,然后进行着色。