Finetune doc and code.

pull/638/head
krahets 1 year ago
parent 76f11ae168
commit 1a55dbdf2e

@ -8,7 +8,6 @@
/* Driver Code */
int main() {
/* 初始化无向图 */
graphAdjList *graph = newGraphAdjList(5);
// 初始化顶点

@ -118,7 +118,6 @@ Vertex **graphBFS(graphAdjList *t, Vertex *startVet) {
resIndex++;
queuePop(que); // 队首元素出队
}
// 释放内存
freeQueue(que);
freeHash(visited);

@ -8,7 +8,7 @@
给定一个二叉树,搜索并记录所有值为 $7$ 的节点,返回节点列表。
**解题思路**前序遍历这颗树,并判断当前节点的值是否为 $7$ ,若是则将该节点的值加入到结果列表 `res` 之中。
对于此题,我们前序遍历这颗树,并判断当前节点的值是否为 $7$ ,若是则将该节点的值加入到结果列表 `res` 之中。
=== "Java"
@ -90,7 +90,7 @@
在二叉树中搜索所有值为 $7$ 的节点,**返回根节点到这些节点的路径**。
**解题思路**在例题一代码的基础上,我们需要借助一个列表 `path` 记录访问过的节点路径。当访问到值为 $7$ 的节点时,则复制 `path` 并添加进结果列表 `res` 。遍历完成后,`res` 中保存的就是所有的解。
在例题一代码的基础上,我们需要借助一个列表 `path` 记录访问过的节点路径。当访问到值为 $7$ 的节点时,则复制 `path` 并添加进结果列表 `res` 。遍历完成后,`res` 中保存的就是所有的解。
=== "Java"
@ -199,12 +199,12 @@
!!! question "例题三"
在二叉树中搜索所有值为 $7$ 的节点,返回根节点到这些节点的路径,**路径中有且只有一个值为 $7$ 的节点,并且不能包含值为 $3$ 的节点**。
在二叉树中搜索所有值为 $7$ 的节点,返回根节点到这些节点的路径,**要求路径中有且只有一个值为 $7$ 的节点,并且不能包含值为 $3$ 的节点**。
**解题思路**:在例题二的基础上添加剪枝操作。
在例题二的基础上添加剪枝操作,包括:
- 当遇到值为 $7$ 的节点时,记录解并止搜索。
- 当遇到值为 $3$ 的节点时,则止继续搜索。
- 当遇到值为 $7$ 的节点时,记录解并返回,终止搜索。
- 当遇到值为 $3$ 的节点时,则直接返回,停止继续搜索。
=== "Java"

@ -29,17 +29,7 @@
![分数背包的贪心策略](fractional_knapsack_problem.assets/fractional_knapsack_greedy_strategy.png)
**第三步:正确性证明**
采用反证法。假设物品 $x$ 是单位价值最高的物品,使用某算法求得最大价值为 $res$ ,但该解中不包含物品 $x$ 。
现在从背包中拿出单位重量的任意物品,并替换为单位重量的物品 $x$ 。由于物品 $x$ 的单位价值最高,因此替换后的总价值一定大于 $res$ 。**这与 $res$ 是最优解矛盾,说明最优解中必须包含物品 $x$ 。**
对于该解中的其他物品,我们也可以构建出上述矛盾。总而言之,**单位价值更大的物品总是更优选择**,这说明贪心策略是有效的。
**实现代码**
我们构建了一个物品类 `Item` ,以便将物品按照单位价值进行排序。在循环贪心选择中,分为放入整个物品或放入部分物品两种情况。当背包已满时,则跳出循环并返回解。
我们构建了一个物品类 `Item` ,以便将物品按照单位价值进行排序。循环进行贪心选择,当背包已满时跳出并返回解。
=== "Java"
@ -129,8 +119,16 @@
[class]{}-[func]{fractionalKnapsack}
```
如下图所示,如果将一个 2D 图表的横轴和纵轴分别看作物品重量和物品单位价值,则分数背包问题可被转化为“求在有限横轴区间下的最大围成面积”。这个类比可以帮助我们从几何角度清晰地看到贪心策略的有效性
最差情况下,需要遍历整个物品列表,**因此时间复杂度为 $O(n)$** ,其中 $n$ 为物品数量。由于初始化了一个 `Item` 对象列表,**因此空间复杂度为 $O(n)$**
![分数背包问题的几何表示](fractional_knapsack_problem.assets/fractional_knapsack_area_chart.png)
**第三步:正确性证明**
最差情况下,需要遍历整个物品列表,**因此时间复杂度为 $O(n)$** ,其中 $n$ 为物品数量。由于初始化了一个 `Item` 对象列表,**因此空间复杂度为 $O(n)$** 。
采用反证法。假设物品 $x$ 是单位价值最高的物品,使用某算法求得最大价值为 $res$ ,但该解中不包含物品 $x$ 。
现在从背包中拿出单位重量的任意物品,并替换为单位重量的物品 $x$ 。由于物品 $x$ 的单位价值最高,因此替换后的总价值一定大于 $res$ 。**这与 $res$ 是最优解矛盾,说明最优解中必须包含物品 $x$ 。**
对于该解中的其他物品,我们也可以构建出上述矛盾。总而言之,**单位价值更大的物品总是更优选择**,这说明贪心策略是有效的。
如下图所示,如果将物品重量和物品单位价值分别看作一个 2D 图表的横轴和纵轴,则分数背包问题可被转化为“求在有限横轴区间下的最大围成面积”。这个类比可以帮助我们从几何角度清晰地看到贪心策略的有效性。
![分数背包问题的几何表示](fractional_knapsack_problem.assets/fractional_knapsack_area_chart.png)

@ -11,7 +11,7 @@
!!! question
给定 $n$ 种硬币,第 $i$ 个硬币的面值为 $coins[i - 1]$ ,目标金额为 $amt$ **每种硬币可以重复选取**,问能够凑出目标金额的最少硬币个数。如果无法凑出目标金额则返回 $-1$ 。
给定 $n$ 种硬币,第 $i$ 个硬币的面值为 $coins[i - 1]$ ,目标金额为 $amt$ ,每种硬币可以重复选取,问能够凑出目标金额的最少硬币个数。如果无法凑出目标金额则返回 $-1$ 。
贪心算法会迭代地做出一个又一个的贪心选择,每轮都将问题转化成一个规模更小的子问题,直到问题被解决。
@ -133,8 +133,8 @@
确定贪心策略是求解问题的核心步骤,但实施起来并没有那么容易。主要有两方面原因:
1. **不同问题的贪心策略的差异较大**。对于许多问题来说,贪心策略都比较浅显,我们通过一些大概的思考与尝试就能得出。而对于一些复杂问题,贪心策略可能非常隐蔽,这种情况就非常考验个人的解题经验与算法能力了。
2. **某些贪心策略具有较强的迷惑性**。当我们满怀信心设计好贪心策略,写出解题代码并提交运行,很可能发现部分测试样例无法通过。这是因为设计的贪心策略只是“部分正确”的,上文介绍的零钱兑换就是个很好的例子。
- **不同问题的贪心策略的差异较大**。对于许多问题来说,贪心策略都比较浅显,我们通过一些大概的思考与尝试就能得出。而对于一些复杂问题,贪心策略可能非常隐蔽,这种情况就非常考验个人的解题经验与算法能力了。
- **某些贪心策略具有较强的迷惑性**。当我们满怀信心设计好贪心策略,写出解题代码并提交运行,很可能发现部分测试样例无法通过。这是因为设计的贪心策略只是“部分正确”的,上文介绍的零钱兑换就是个很好的例子。
为了保证正确性,我们应该对贪心策略进行严谨的数学证明,**通常需要用到反证法或数学归纳法**。

Loading…
Cancel
Save