Update H1 titles.

This commit is contained in:
krahets
2023-08-20 13:37:49 +08:00
parent 70227c82cb
commit 5fb728b3d6
5 changed files with 118 additions and 108 deletions
@@ -26,10 +26,10 @@
由于实际测试具有较大的局限性,我们可以考虑仅通过一些计算来评估算法的效率。这种估算方法被称为「渐近复杂度分析 Asymptotic Complexity Analysis」,简称为「复杂度分析」。
**复杂度分析评估的是算法运行效率随着输入数据量增多时的增长趋势**。这个定义有些拗口,我们可以将其分为三个重点来理解:
复杂度分析评估的是算法执行所需的时间和空间资源。**它被表示为一个函数,描述了随着输入数据大小的增加,算法所需时间(空间)的增长趋势**。这个定义有些拗口,我们可以将其分为三个重点来理解:
1.算法运行效率”可分为运行时间和占用空间两部分,与之对应地,复杂度可分为「时间复杂度 Time Complexity」和「空间复杂度 Space Complexity」。
2. “随着输入数据量增多时”意味着复杂度反映了算法运行效率与输入数据量之间的关系。
1.时间(空间)”分别对应「时间复杂度 Time Complexity」和「空间复杂度 Space Complexity」。
2. “随着输入数据大小的增加”意味着复杂度反映了算法运行效率与输入数据量之间的关系。
3. “增长趋势”表示复杂度分析关注的是算法时间与空间的增长趋势,而非具体的运行时间或占用空间。
**复杂度分析克服了实际测试方法的弊端**。首先,它独立于测试环境,分析结果适用于所有运行平台。其次,它可以体现不同数据量下的算法效率,尤其是在大数据量下的算法性能。
@@ -20,6 +20,8 @@
![基于决策树模型表示编辑距离问题](edit_distance_problem.assets/edit_distance_decision_tree.png)
### 动态规划思路
**第一步:思考每轮的决策,定义状态,从而得到 $dp$ 表**
每一轮的决策是对字符串 $s$ 进行一次编辑操作。
@@ -10,6 +10,8 @@
![完全背包问题的示例数据](unbounded_knapsack_problem.assets/unbounded_knapsack_example.png)
### 动态规划思路
完全背包和 0-1 背包问题非常相似,**区别仅在于不限制物品的选择次数**。
- 在 0-1 背包中,每个物品只有一个,因此将物品 $i$ 放入背包后,只能从前 $i-1$ 个物品中选择。
@@ -210,6 +212,8 @@ $$
![零钱兑换问题的示例数据](unbounded_knapsack_problem.assets/coin_change_example.png)
### 动态规划思路
**零钱兑换可以看作是完全背包的一种特殊情况**,两者具有以下联系与不同点:
- 两道题可以相互转换,“物品”对应于“硬币”、“物品重量”对应于“硬币面值”、“背包容量”对应于“目标金额”。
@@ -450,6 +454,8 @@ $$
![零钱兑换问题 II 的示例数据](unbounded_knapsack_problem.assets/coin_change_ii_example.png)
### 动态规划思路
相比于上一题,本题目标是组合数量,因此子问题变为:**前 $i$ 种硬币能够凑出金额 $a$ 的组合数量**。而 $dp$ 表仍然是尺寸为 $(n+1) \times (amt + 1)$ 的二维矩阵。
当前状态的组合数量等于不选当前硬币与选当前硬币这两种决策的组合数量之和。状态转移方程为:
+8 -6
View File
@@ -1,16 +1,18 @@
# 建堆操作
如果我们想要根据输入列表生成一个堆,这个过程被称为「建堆」。
在某些情况下,我们希望使用一个列表的所有元素来构建一个堆,这个过程被称为「建堆」。
## 借助入堆方法实现
最直接的方法是借助“元素入堆操作”实现首先创建一个空堆,然后将列表元素依次添加到堆中
最直接的方法是借助“元素入堆操作”实现。我们首先创建一个空堆,然后将列表元素依次执行“入堆”
设元素数量为 $n$ 则最后一个元素入堆的时间复杂度为 $O(\log n)$ 。在依次添加元素时,堆的平均长度为 $\frac{n}{2}$ ,因此该方法的总体时间复杂度为 $O(n \log n)$ 。
设元素数量为 $n$ 入堆操作使用 $O(\log{n})$ 时间,因此将所有元素入堆的时间复杂度为 $O(n \log n)$ 。
## 基于堆化操作实现
有趣的是,存在一种更高效的建堆方法,其时间复杂度仅为 $O(n)$ 。我们先将列表所有元素原封不动添加到堆中,**然后迭代地对各个节点执行“从顶至底堆化”**。当然,**我们不需要对叶节点执行堆化操作**,因为它们没有子节点
有趣的是,存在一种更高效的建堆方法,其时间复杂度可以达到 $O(n)$ 。我们先将列表所有元素原封不动添加到堆中,然后倒序遍历该堆,依次对每个节点执行“从顶至底堆化”
请注意,因为叶节点没有子节点,所以无需堆化。在代码实现中,我们从最后一个节点的父节点开始进行堆化。
=== "Java"
@@ -88,7 +90,7 @@
为什么第二种建堆方法的时间复杂度是 $O(n)$ ?我们来展开推算一下。
- 完全二叉树中,设节点总数为 $n$ ,则叶节点数量为 $(n + 1) / 2$ ,其中 $/$ 为向下整除。因此,在排除叶节点后,需要堆化的节点数量为 $(n - 1)/2$ ,复杂度为 $O(n)$ 。
- 完全二叉树中,设节点总数为 $n$ ,则叶节点数量为 $(n + 1) / 2$ ,其中 $/$ 为向下整除。因此,在排除叶节点后,需要堆化的节点数量为 $(n - 1)/2$ ,复杂度为 $O(n)$ 。
- 在从顶至底堆化的过程中,每个节点最多堆化到叶节点,因此最大迭代次数为二叉树高度 $O(\log n)$ 。
将上述两者相乘,可得到建堆过程的时间复杂度为 $O(n \log n)$ 。**然而,这个估算结果并不准确,因为我们没有考虑到二叉树底层节点数量远多于顶层节点的特性**。
@@ -112,7 +114,7 @@ T(h) & = 2^0h + 2^1(h-1) + 2^2(h-2) + \cdots + 2^{h-1}\times1 \newline
\end{aligned}
$$
**使用错位相减法**,令下式 $2 T(h)$ 减去上式 $T(h)$ ,可得
使用错位相减法,用下式 $2 T(h)$ 减去上式 $T(h)$ ,可得
$$
2T(h) - T(h) = T(h) = -2^0h + 2^1 + 2^2 + \cdots + 2^{h-1} + 2^h