This commit is contained in:
krahets
2023-08-20 13:37:08 +08:00
parent 2e27ad1680
commit 44a8568356
32 changed files with 140 additions and 130 deletions

View File

@@ -23,7 +23,7 @@ status: new
分治能够提升搜索效率,本质上是因为暴力搜索每轮只能排除一个选项,**而分治搜索每轮可以排除一半选项**。
### 基于分治实现二分
### 1.   基于分治实现二分
在之前的章节中,二分查找是基于递推(迭代)实现的。现在我们基于分治(递归)来实现它。

View File

@@ -13,7 +13,7 @@ status: new
<p align="center"> 图:构建二叉树的示例数据 </p>
### 判断是否为分治问题
### 1. &nbsp; 判断是否为分治问题
原问题定义为从 `preorder``inorder` 构建二叉树。我们首先从分治的角度分析这道题:
@@ -21,7 +21,7 @@ status: new
- **子问题是独立的**:左子树和右子树是相互独立的,它们之间没有交集。在构建左子树时,我们只需要关注中序遍历和前序遍历中与左子树对应的部分。右子树同理。
- **子问题的解可以合并**:一旦得到了左子树和右子树(子问题的解),我们就可以将它们链接到根节点上,得到原问题的解。
### 如何划分子树
### 2. &nbsp; 如何划分子树
根据以上分析,这道题是可以使用分治来求解的,但问题是:**如何通过前序遍历 `preorder` 和中序遍历 `inorder` 来划分左子树和右子树呢**
@@ -40,7 +40,7 @@ status: new
<p align="center"> 图:在前序和中序遍历中划分子树 </p>
### 基于变量描述子树区间
### 3. &nbsp; 基于变量描述子树区间
根据以上划分方法,**我们已经得到根节点、左子树、右子树在 `preorder``inorder` 中的索引区间**。而为了描述这些索引区间,我们需要借助几个指针变量:
@@ -67,7 +67,7 @@ status: new
<p align="center"> 图:根节点和左右子树的索引区间表示 </p>
### 代码实现
### 4. &nbsp; 代码实现
为了提升查询 $m$ 的效率,我们借助一个哈希表 `hmap` 来存储数组 `inorder` 中元素到索引的映射。

View File

@@ -39,7 +39,7 @@ status: new
那么,我们不禁发问:**为什么分治可以提升算法效率,其底层逻辑是什么**?换句话说,将大问题分解为多个子问题、解决子问题、将子问题的解合并为原问题的解,这几步的效率为什么比直接解决原问题的效率更高?这个问题可以从操作数量和并行计算两方面来讨论。
### 操作数量优化
### 1. &nbsp; 操作数量优化
以「冒泡排序」为例,其处理一个长度为 $n$ 的数组需要 $O(n^2)$ 时间。假设我们把数组从中点分为两个子数组,则划分需要 $O(n)$ 时间,排序每个子数组需要 $O((\frac{n}{2})^2)$ 时间,合并两个子数组需要 $O(n)$ 时间,总体时间复杂度为:
@@ -67,7 +67,7 @@ $$
再思考,**如果我们多设置几个划分点**,将原数组平均划分为 $k$ 个子数组呢?这种情况与「桶排序」非常类似,它非常适合排序海量数据,理论上时间复杂度可以达到 $O(n + k)$ 。
### 并行计算优化
### 2. &nbsp; 并行计算优化
我们知道,分治生成的子问题是相互独立的,**因此通常可以并行解决**。也就是说,分治不仅可以降低算法的时间复杂度,**还有利于操作系统的并行优化**。

View File

@@ -21,7 +21,7 @@ status: new
**我们将规模为 $i$ 的汉诺塔问题记做 $f(i)$** 。例如 $f(3)$ 代表将 $3$ 个圆盘从 `A` 移动至 `C` 的汉诺塔问题。
### 考虑基本情况
### 1. &nbsp; 考虑基本情况
对于问题 $f(1)$ ,即当只有一个圆盘时,则将它直接从 `A` 移动至 `C` 即可。
@@ -55,7 +55,7 @@ status: new
<p align="center"> 图:规模为 2 问题的解 </p>
### 子问题分解
### 2. &nbsp; 子问题分解
对于问题 $f(3)$ ,即当有三个圆盘时,情况变得稍微复杂了一些。由于已知 $f(1)$ 和 $f(2)$ 的解,因此可从分治角度思考,**将 `A` 顶部的两个圆盘看做一个整体**,执行以下步骤:
@@ -93,7 +93,7 @@ status: new
<p align="center"> 图:汉诺塔问题的分治策略 </p>
### 代码实现
### 3. &nbsp; 代码实现
在代码中,我们声明一个递归函数 `dfs(i, src, buf, tar)` ,它的作用是将柱 `src` 顶部的 $i$ 个圆盘借助缓冲柱 `buf` 移动至目标柱 `tar`