目录
[a.如果我们用第二个参数n的规模来度量m和n的最大公约数问题的实例规模,在用欧几里得算法计算 gcd(m,n)时,实例的规模会消减多少?](#a.如果我们用第二个参数n的规模来度量m和n的最大公约数问题的实例规模,在用欧几里得算法计算 gcd(m,n)时,实例的规模会消减多少?)
b.请证明,在欧几里得算法做了两次连续的迭代以后,实例的规模总是会至少消去一个大于2的因子。
[2. 应用快速选择算法求数列9,12,5,17,20,30,8的中位数。](#2. 应用快速选择算法求数列9,12,5,17,20,30,8的中位数。)
5.给出插值查找最差输入的一个例子,并说明该算法在最差情况下是线性的。
[a. 为了使log₂log₂n+1大于6, n的最小值是多少?](#a. 为了使log₂log₂n+1大于6, n的最小值是多少?)
a.描述一个在二叉查找树中寻找最大键的算法。你会把你的算法归类为减可变规模算法吗?
a.描述一个在二叉查找树中删除一个键的算法。你会把你的算法归类为减可变规模算法吗?
9.对于所有顶点连通度都是偶数的连通图,给出构造其欧拉回路的减可变规模算法。
[10.另类单堆拈游戏 请考虑这个另类的单堆拈游戏,它规定谁拿走最后一个棋子就输了。该游戏的其他条件都不变,即该堆棋子有n个,每次每个玩家最多拿走m个,最少拿走 1 个棋子。请指出该游戏的胜局和败局(对于接下来要走的玩家来说)是怎样的?](#10.另类单堆拈游戏 请考虑这个另类的单堆拈游戏,它规定谁拿走最后一个棋子就输了。该游戏的其他条件都不变,即该堆棋子有n个,每次每个玩家最多拿走m个,最少拿走 1 个棋子。请指出该游戏的胜局和败局(对于接下来要走的玩家来说)是怎样的?)
[a.坏巧克力 两个玩家轮流掰一块m×n格的巧克力,其中一块1×1的小块是坏的。每次掰只能顺着方格的边界,沿直线一掰到底。每掰一次,掰的人把两块中不含坏巧克力的那块吃掉,谁碰到最后那块坏巧克力就算输了。在这个游戏中,先走好还是后走好?](#a.坏巧克力 两个玩家轮流掰一块m×n格的巧克力,其中一块1×1的小块是坏的。每次掰只能顺着方格的边界,沿直线一掰到底。每掰一次,掰的人把两块中不含坏巧克力的那块吃掉,谁碰到最后那块坏巧克力就算输了。在这个游戏中,先走好还是后走好?)
[12.翻薄饼 有n张大小各不相同的薄饼,一张叠在另一张上面。允许大家把一个翻板插到一个薄饼下面,然后可以把板上面的这叠薄饼翻个身。我们的目标是根据薄饼的大小重新安排它们的位置,最大的饼要放在最下面。大家可以在网站"Interactive Mathematics Miscellany and Puzzles"(交互式的数学杂题和智力游戏)上找到该游戏的一个动态演示([Bogl)。设计一个算法来解这个谜题。](#12.翻薄饼 有n张大小各不相同的薄饼,一张叠在另一张上面。允许大家把一个翻板插到一个薄饼下面,然后可以把板上面的这叠薄饼翻个身。我们的目标是根据薄饼的大小重新安排它们的位置,最大的饼要放在最下面。大家可以在网站“Interactive Mathematics Miscellany and Puzzles”(交互式的数学杂题和智力游戏)上找到该游戏的一个动态演示([Bogl)。设计一个算法来解这个谜题。)
13.假设需要在一个n×n矩阵中搜索一个给定数字,该矩阵每行每列都按升序排列。你能为这个问题设计一个O(n)算法吗?([Laa10])
1.
a.如果我们用第二个参数n的规模来度量m和n的最大公约数问题的实例规模,在用欧几里得算法计算 gcd(m,n)时,实例的规模会消减多少?
规模从 n 变成 m mod n,
而 m mod n < n ,规模至少减少到n-1。
b.请证明,在欧几里得算法做了两次连续的迭代以后,实例的规模总是会至少消去一个大于2的因子。
在前一个m%n=r的前提下,我们假设两种情况:
1.r<=n/2,则此时已经消去了至少2的因子
2.r>n/2,此时情况下,进行下一步取模,有r1=n%r,因为r>n/2,所以r1=n-r<n/2。此时也消减了2的因子
2. 应用快速选择算法求数列9,12,5,17,20,30,8的中位数。
数组:[9,12,5,17,20,30,8],pivot = 9
分区过程:
一:s=l,i=l+1;
12>9,则i+1
5<9,s+1, 然后A[s]与A[i]交换
随后的17,20,30都大于9,直到8小于9,s再+1,交换A[s]与A[i]
最后交换A[s]与A[l]

此时s=2,并不是中位数,因此从右边继续找第1个(4-(2+1))

第二轮后,s=4,则找左边的第1个

最终找到中位数12,s=3
3.请写出非递归快速选择算法的伪代码。
算法:IterativeQuickSelect(A[0..n-1], k)
// 输入:数组A,整数k(1 ≤ k ≤ n)
// 输出:数组中第k小的元素
// 非递归快速选择,使用Lomuto划分
low ← 0
high ← n - 1
while low ≤ high do
// 1. Lomuto 划分
pivot ← A[high] // 选最右侧元素为基准
i ← low - 1 // 小于区指针
for j ← low to high-1 do
if A[j] ≤ pivot then
i ← i + 1
交换 A[i] 和 A[j]
// 把基准放到正确位置
交换 A[i+1] 和 A[high]
pos ← i + 1 // 基准最终下标
// 2. 判断目标位置
if pos == k - 1 then // 找到第k小
return A[pos]
else if pos > k - 1 then // 目标在左半区
high ← pos - 1
else // 目标在右半区
low ← pos + 1
// 理论上不会执行到这里
return -1
4.推导插值查找算法的公式。
通过两点之间直线:

代入给定y=v:移项求出x

5.给出插值查找最差输入的一个例子,并说明该算法在最差情况下是线性的。
数组元素呈指数增长 / 极小值在前,极大值在后
数组 A = [1, 2, 4, 8, 16, 32, 64, ..., 2ⁿ⁻¹],查找的 key = 2(数组里第二个元素)
此时:


从效果来看和顺序遍历没有区别了',每次计算出的 mid 都非常靠近 low ,查找区间每次只缩小 1 ,必须执行 n 次 比较。因此,最差时间效率为线性阶 O (n)。
6.
a. 为了使log₂log₂n+1大于6, n的最小值是多少?
n>2^32
b.下列断言中哪些是正确的?
i. loglogn∈o(logn) ii. loglogn∈Θ(logn) iii. loglogn∈Ω(logn)
只有第一个是正确的,可以用极限得出差距
7.
a.描述一个在二叉查找树中寻找最大键的算法。你会把你的算法归类为减可变规模算法吗?
- 从根节点出发。
- 如果当前节点的右孩子不为空 ,就一直向右走。
- 当右孩子为空时,当前节点的键就是最大键。
显然是减可变规模的,
- 每一步都抛弃左子树 + 根 ,只保留右子树继续处理。
- 问题规模每次都在减小,但减小多少不固定(取决于树的形状)。
- 符合 ** 减可变规模(decrease-by-variable)** 算法的定义。
b.你的算法在最坏情况下的效率类型是哪一种?
树退化成一条右斜链(链表)。此时需要一直向右子树遍历,效率达到了Θ(n)
8.
a.描述一个在二叉查找树中删除一个键的算法。你会把你的算法归类为减可变规模算法吗?
设要删除节点为 p,其父节点为 parent:
- **情况 1:p 是叶子节点(无孩子)**直接将父节点指向它的指针置空。
- **情况 2:p 只有一个孩子(左或右)**用其唯一孩子替代 p 的位置。
- 情况 3:p 有两个孩子
- 找到 p 左子树的最大值(或右子树最小值)
- 用这个值替换 p 的值
- 再删除那个被复制的节点
是减可变规模的,
- 删除操作每一步都会减少节点总数 1 个
- 但查找节点、找前驱 / 后继的过程中,问题规模减小量不固定
- 因此属于 减可变规模(decrease-by-variable)算法
b.你的算法在最坏情况下的效率类型是哪一种?
二叉查找树退化成斜树(链表)。
- 查找要删除的节点:Θ(n)
- 若有两个孩子,找前驱 / 后继:Θ(n)
9.对于所有顶点连通度都是偶数的连通图,给出构造其欧拉回路的减可变规模算法。
- 从任意顶点 出发,沿着未使用的边行走,直到回到起点,形成一个回路 C。
- 如果回路 C 包含了所有边,算法结束,C 就是欧拉回路。
- 否则,在回路 C 中找到一个还有未使用边的顶点 u。
- 从 u 出发,用剩余边 构造一个新的回路 D。
- 把 D 插入到 C 中 u 的位置,合并成一个更大的回路。
- 重复步骤 2--5,直到所有边都被使用。
显然是减可变规模的:
- 每一步都删除已使用的边,问题规模(剩余边数)不断减小。
- 每次减小的边数不固定(取决于找到的回路长度)。
- 属于减可变规模(decrease-by-variable)。
10.另类单堆拈游戏 请考虑这个另类的单堆拈游戏,它规定谁拿走最后一个棋子就输了。该游戏的其他条件都不变,即该堆棋子有n个,每次每个玩家最多拿走m个,最少拿走 1 个棋子。请指出该游戏的胜局和败局(对于接下来要走的玩家来说)是怎样的?
也就是把题目理解成n-1个,最后拿不到棋子的就输了,则n-1=k(m+1)时,先手必输,只要n!=k(m+1)+1则必赢
11.
a.坏巧克力 两个玩家轮流掰一块m×n格的巧克力,其中一块1×1的小块是坏的。每次掰只能顺着方格的边界,沿直线一掰到底。每掰一次,掰的人把两块中不含坏巧克力的那块吃掉,谁碰到最后那块坏巧克力就算输了。在这个游戏中,先走好还是后走好?
只有一种情况后手必胜:坏巧克力在左上角(1,1),且巧克力是正方形 m×m。 其余所有情况,先手都有必胜策略。
- 坏巧克力把巧克力分成左 / 上 两条边:
x(左边距离)、y(上边距离) - 游戏等价于取石子游戏 :两个堆
x和y - 先手必胜:
x ≠ y - 后手必胜:
x = y(正方形且坏角在左上)
12.翻薄饼 有n张大小各不相同的薄饼,一张叠在另一张上面。允许大家把一个翻板插到一个薄饼下面,然后可以把板上面的这叠薄饼翻个身。我们的目标是根据薄饼的大小重新安排它们的位置,最大的饼要放在最下面。大家可以在网站"Interactive Mathematics Miscellany and Puzzles"(交互式的数学杂题和智力游戏)上找到该游戏的一个动态演示([Bogl)。设计一个算法来解这个谜题。
每次将当前最大的饼先翻到最上面,再翻到当前最底部,重复此过程,每次使问题规模减 1,直到全部有序。
- 最多翻转次数:2n − 3
- 时间效率:O(n²)
13.假设需要在一个n×n矩阵中搜索一个给定数字,该矩阵每行每列都按升序排列。你能为这个问题设计一个O(n)算法吗?([Laa10])
- 设当前位置为 最右上角 :
row = 0,col = n-1 - 当
row < n 且 col ≥ 0:- 如果 当前值 == key → 找到,返回位置
- 如果 当前值 > key → 向左走一列(排除当前列)
- 如果 当前值 < key → 向下走一行(排除当前行)
- 越界仍未找到 → 不存在
最多走 n 步向下 + n 步向左,最多是2n,效率为线性