1. 递归的概念
例1 阶乘函数
n ! = { 1 n = 0 n ( n − 1 ) ! n > 0 n! = \begin{cases} \ 1 & n=0 \\ n(n-1)! & n>0 \\ \end{cases} n!={ 1n(n−1)!n=0n>0
其中 n = 0 n=0 n=0是边界条件, n ( n − 1 ) ! n > 0 n(n-1)! n>0 n(n−1)!n>0是递归方程,这是递归函数的两个要素。
例2 Fibonacci数列
F ( n ) = { 1 n = 0 1 n = 1 F ( n − 1 ) + F ( n − 2 ) n > 1 F(n) = \begin{cases} \ 1 & n=0 \\ 1 & n=1 \\ F(n-1)+F(n-2) & n>1 \\ \end{cases} F(n)=⎩⎪⎨⎪⎧ 11F(n−1)+F(n−2)n=0n=1n>1
例3 整数划分问题
将正整数n表示成一系列正整数之和:
n
=
n
1
+
n
2
+
.
.
.
+
n
k
n=n_{1}+n_{2}+...+n_{k}
n=n1+n2+...+nk,其中
n
1
⩾
n
2
⩾
.
.
.
⩾
n
k
⩾
1
,
k
⩾
1
n_{1} \geqslant n_{2} \geqslant ... \geqslant n_{k} \geqslant 1,k\geqslant 1
n1⩾n2⩾...⩾nk⩾1,k⩾1。
正整数
n
n
n的这种表示称为正整数n的划分。求正整数
n
n
n的不同划分个数。
例如正整数6有如下11种不同的划分:
6;
5+1;
4+2,4+1+1;
3+3,3+2+1,3+1+1+1;
2+2+2,2+2+1+1,2+1+1+1+1;
1+1+1+1+1+1.
设 p ( n , m ) p(n,m) p(n,m)为最大加数 n 1 n_{1} n1不大于 m m m的划分个数,则
(1) q ( n , 1 ) = 1 , n ⩾ 1 ; q(n,1)=1,n \geqslant 1; q(n,1)=1,n⩾1;
当最大加数 n 1 n_{1} n1不大于1时,任何正整数只有一种划分形式,即
n = 1 + 1 + 1 + ⋯ + 1 ⏞ n n=\overbrace{1+1+1+\cdots+1}^{\rm n} n=1+1+1+⋯+1 n
(2) q ( n , m ) = q ( n , n ) , m ⩾ n ; q(n,m)=q(n,n),m\geqslant n; q(n,m)=q(n,n),m⩾n;
最大加数 n 1 n_{1} n1实际上不能大于n。因此, q ( 1 , m ) = 1 。 q(1,m)=1。 q(1,m)=1。
(3) q ( n , n ) = 1 + q ( n , n − 1 ) ; q(n,n)=1+q(n,n-1); q(n,n)=1+q(n,n−1);
正整数 n n n的划分由 n 1 = n n_{1}=n n1=n的划分和 n 1 ⩽ n − 1 n_{1}\leqslant n-1 n1⩽n−1的划分组成。
(4) q ( n , m ) = q ( n , m − 1 ) + q ( n − m , m ) , n > m > 1 ; q(n,m)=q(n,m-1)+q(n-m,m),n>m>1; q(n,m)=q(n,m−1)+q(n−m,m),n>m>1;
正整数 n n n的最大加数 n 1 n_{1} n1不大于 m m m的划分由 n 1 = m n_{1}=m n1=m的划分和 n 1 ⩽ m − 1 n_{1}\leqslant m-1 n1⩽m−1的划分组成。
由此可以得到:
q ( n , m ) = { 1 n = 1 , m = 1 q ( n , n ) n < m 1 + q ( n , n − 1 ) n = m q ( n , m − 1 ) + q ( n − m , m ) n > m > 1 q(n,m) = \begin{cases} \ 1 & n=1,m=1 \\ q(n,n) & n<m \\ 1+q(n,n-1) & n=m \\ q(n,m-1)+q(n-m,m) &n>m>1\\ \end{cases} q(n,m)=⎩⎪⎪⎪⎨⎪⎪⎪⎧ 1q(n,n)1+q(n,n−1)q(n,m−1)+q(n−m,m)n=1,m=1n<mn=mn>m>1
正整数 n n n的划分数 p ( n ) = q ( n , n ) . p(n)=q(n,n). p(n)=q(n,n).
例4 Hanoi塔
把盘子1~n由A移动到C,分三个阶段:
- 把盘子1~n-1由A移动到B
- 把盘子n由A移动到C
- 把盘子1~n-1由B移动到C
在这里我们把盘子1~n-1的移动看作一个整体移动
2.分治法
总体思想:将求出的小规模的问题的解合并为一个更大规模的问题的解,自底向上逐步求出原来问题的解。
由分治法产生的子问题往往是原问题的较小模式,使用递归技术,使子问题与原问题类型一致而其规模却不断缩小。
分治法的适用条件
分治法所能解决的问题一般具有以下几个特征:
- 该问题的规模缩小到一定的程度就可以容易地解决;
- 该问题可以分解为若干个规模较小的相同问题,即该问题具有最优子结构性质;
- 利用该问题分解出的子问题的解可以合并为该问题的解。
3.二分搜索技术
二分搜索算法是运用分治策略的典型例子。给定已排好序的n个元素a[0:n-1],现要在这n个元素中找出一特定元素x。
基本思想是,将n个元素分成个数大致相等的两半,取a[n/2]与x作比较。如果x=a[n/2],则找到x,算法终止;如果x<a[n/2],则只在数组a的左半部继续搜索x;如果x>a[n/2],则只在数组a的右半部继续搜索x。
4.棋盘覆盖
在一个
2
k
×
2
k
(
k
⩾
0
)
2^{k}\times 2^{k}(k\geqslant 0)
2k×2k(k⩾0)个方格组成的棋盘中,恰有一个方格与其他方格不同,称该方格为特殊方格,显然,特殊方格在棋盘中出现的位置有
4
k
4^{k}
4k种不同的情形,因而有
4
k
4^{k}
4k种不同的棋盘。
在棋盘覆盖问题中,需要用4种不同形态的L型三格骨牌覆盖一个给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重复覆盖。易知,在任何一个
2
k
×
2
k
2^{k}\times 2^{k}
2k×2k的棋盘覆盖中,用到的L型骨牌个数恰为
(
4
k
)
/
3
(4^{k})/3
(4k)/3。
(1)当k>0时,将
2
k
×
2
k
2^{k}\times 2^{k}
2k×2k棋盘分割为4个
2
k
−
1
×
2
k
−
1
2^{k-1}\times 2^{k-1}
2k−1×2k−1子棋盘
(2)用一个L型骨牌覆盖这3个较小棋盘的结合处
5.合并排序
将待排序元素分成大小大致相同的两个子集合,分别对两个子集合进行排序,最终将排好序的子集合合并成要求的排好序的集合。时间复杂度是o(nlogn)
6.快速排序
快速排序是一种基于划分的排序方法;
划分:选取待分类集合A中的某个元素t,按照与t的大小关系重新整理A中元素,使得整理后的序列中所有在t以前出现的元素均小于等于t,而所有在t以后的元素均大于等于t。这一元素的整理过程称为划分。元素t称为划分元素。
算法过程:设要排序的数组是A[0]…A[N-1],首先任意选取一个数据(通常选用第一个数据)作为关键数据,然后将所有比它小的数都放到它前面,所有比它大的数都放到它后面,这个过程称为一趟快速排序。
7.选择问题
选最大: 顺序比较
选最大和最小: 分组算法
分组算法:
- 将n个元素两两一组分成 ⌊ n / 2 ⌋ \lfloor n/2\rfloor ⌊n/2⌋组
- 每组比较,得到 ⌊ n / 2 ⌋ \lfloor n/2\rfloor ⌊n/2⌋个较小和 ⌊ n / 2 ⌋ \lfloor n/2\rfloor ⌊n/2⌋个较大
- 在 ⌈ n / 2 ⌉ \lceil n/2\rceil ⌈n/2⌉个较大(含轮空元素)中找最大max
- 在 ⌈ n / 2 ⌉ \lceil n/2\rceil ⌈n/2⌉个较小(含轮空元素)中找最小min
选第二大: 顺序比较、锦标赛算法
锦标赛算法:
- 两两分组比较,大者进入下一轮,直到剩下1个元素max为止
- 在每次比较中淘汰较小元素,将被淘汰元素记录在淘汰它的元素的链表上
- 检查max的链表,从中找到最大元,即second
选第k小: 1.调用k次选最小算法;2.先排序,然后输出第k小的数
分治算法:
- 将n个元素分为 ⌈ n / 5 ⌉ \lceil n/5\rceil ⌈n/5⌉组,每组按从大到小的顺序排好
- 将每组中间元素按从小到大的顺序排好,中间元素移动时其余元素也跟着移动
最终结果如图所示:
若A的组数为r组,则A中元素为2r,B中元素为3r+2,C中元素为3r+2,D中元素为2r。这样可以根据k的大小选择对应的区。