From 2c96e433e24cda8d6953b88157ca428e95ba3b08 Mon Sep 17 00:00:00 2001 From: krahets Date: Tue, 11 Jul 2023 19:21:38 +0800 Subject: [PATCH] deploy --- 404.html | 16 + chapter_appendix/contribution/index.html | 16 + chapter_appendix/installation/index.html | 22 +- chapter_array_and_linkedlist/array/index.html | 16 + chapter_array_and_linkedlist/index.html | 16 + .../linked_list/index.html | 16 + chapter_array_and_linkedlist/list/index.html | 16 + .../summary/index.html | 16 + .../backtracking_algorithm/index.html | 48 +- chapter_backtracking/index.html | 16 + .../n_queens_problem/index.html | 16 + .../permutations_problem/index.html | 22 +- .../subset_sum_problem/index.html | 16 + chapter_backtracking/summary/index.html | 16 + chapter_computational_complexity/index.html | 16 + .../performance_evaluation/index.html | 16 + .../space_complexity/index.html | 16 + .../summary/index.html | 16 + .../time_complexity/index.html | 16 + .../basic_data_types/index.html | 32 +- .../character_encoding/index.html | 16 + .../index.html | 30 +- chapter_data_structure/index.html | 16 + .../number_encoding/index.html | 16 + chapter_data_structure/summary/index.html | 16 + .../climbing_stairs_constraint_example.png | Bin ...mbing_stairs_constraint_state_transfer.png | Bin .../min_cost_cs_dp.png | Bin .../min_cost_cs_example.png | Bin .../dp_problem_features/index.html | 24 +- .../dp_solution_pipeline/index.html | 20 +- chapter_dynamic_programming/index.html | 16 + .../intro_to_dynamic_programming/index.html | 16 + .../knapsack_problem/index.html | 38 +- .../coin_change_dp_step1.png | Bin 0 -> 62488 bytes .../coin_change_dp_step10.png | Bin 0 -> 66659 bytes .../coin_change_dp_step11.png | Bin 0 -> 65281 bytes .../coin_change_dp_step12.png | Bin 0 -> 65664 bytes .../coin_change_dp_step13.png | Bin 0 -> 66014 bytes .../coin_change_dp_step14.png | Bin 0 -> 65685 bytes .../coin_change_dp_step15.png | Bin 0 -> 58827 bytes .../coin_change_dp_step2.png | Bin 0 -> 64473 bytes .../coin_change_dp_step3.png | Bin 0 -> 66980 bytes .../coin_change_dp_step4.png | Bin 0 -> 67091 bytes .../coin_change_dp_step5.png | Bin 0 -> 67371 bytes .../coin_change_dp_step6.png | Bin 0 -> 67380 bytes .../coin_change_dp_step7.png | Bin 0 -> 65428 bytes .../coin_change_dp_step8.png | Bin 0 -> 66609 bytes .../coin_change_dp_step9.png | Bin 0 -> 66803 bytes .../coin_change_example.png | Bin 0 -> 55454 bytes .../coin_change_ii_example.png | Bin 0 -> 63093 bytes .../unbounded_knapsack_dp_comp_step1.png | Bin 0 -> 66784 bytes .../unbounded_knapsack_dp_comp_step2.png | Bin 0 -> 67442 bytes .../unbounded_knapsack_dp_comp_step3.png | Bin 0 -> 68946 bytes .../unbounded_knapsack_dp_comp_step4.png | Bin 0 -> 69343 bytes .../unbounded_knapsack_dp_comp_step5.png | Bin 0 -> 68784 bytes .../unbounded_knapsack_dp_comp_step6.png | Bin 0 -> 69037 bytes .../unbounded_knapsack_example.png | Bin 0 -> 70520 bytes .../unbounded_knapsack_problem/index.html | 3202 +++++++++++++++++ chapter_graph/graph/index.html | 16 + chapter_graph/graph_operations/index.html | 16 + chapter_graph/graph_traversal/index.html | 16 + chapter_graph/index.html | 16 + chapter_graph/summary/index.html | 16 + chapter_hashing/hash_algorithm/index.html | 16 + chapter_hashing/hash_collision/index.html | 16 + chapter_hashing/hash_map/index.html | 16 + chapter_hashing/index.html | 16 + chapter_hashing/summary/index.html | 16 + chapter_heap/build_heap/index.html | 16 + chapter_heap/heap/index.html | 16 + chapter_heap/index.html | 16 + chapter_heap/summary/index.html | 16 + chapter_heap/top_k/index.html | 16 + .../algorithms_are_everywhere/index.html | 16 + chapter_introduction/index.html | 16 + chapter_introduction/summary/index.html | 16 + chapter_introduction/what_is_dsa/index.html | 16 + chapter_preface/about_the_book/index.html | 16 + chapter_preface/index.html | 16 + chapter_preface/suggestions/index.html | 16 + chapter_preface/summary/index.html | 16 + chapter_reference/index.html | 16 + chapter_searching/binary_search/index.html | 16 + .../binary_search_edge/index.html | 16 + chapter_searching/index.html | 16 + .../replace_linear_by_hashing/index.html | 16 + .../searching_algorithm_revisited/index.html | 16 + chapter_searching/summary/index.html | 16 + chapter_sorting/bubble_sort/index.html | 16 + chapter_sorting/bucket_sort/index.html | 16 + chapter_sorting/counting_sort/index.html | 16 + chapter_sorting/heap_sort/index.html | 16 + chapter_sorting/index.html | 16 + chapter_sorting/insertion_sort/index.html | 16 + chapter_sorting/merge_sort/index.html | 16 + chapter_sorting/quick_sort/index.html | 16 + chapter_sorting/radix_sort/index.html | 16 + chapter_sorting/selection_sort/index.html | 16 + chapter_sorting/sorting_algorithm/index.html | 16 + chapter_sorting/summary/index.html | 16 + chapter_stack_and_queue/deque/index.html | 16 + chapter_stack_and_queue/index.html | 16 + chapter_stack_and_queue/queue/index.html | 16 + chapter_stack_and_queue/stack/index.html | 16 + chapter_stack_and_queue/summary/index.html | 16 + .../array_representation_of_tree/index.html | 16 + chapter_tree/avl_tree/index.html | 16 + chapter_tree/binary_search_tree/index.html | 16 + chapter_tree/binary_tree/index.html | 16 + chapter_tree/binary_tree_traversal/index.html | 16 + chapter_tree/index.html | 16 + chapter_tree/summary/index.html | 16 + index.html | 16 + search/search_index.json | 2 +- sitemap.xml | 173 +- sitemap.xml.gz | Bin 836 -> 847 bytes 117 files changed, 4713 insertions(+), 132 deletions(-) rename chapter_dynamic_programming/{intro_to_dynamic_programming.assets => dp_problem_features.assets}/climbing_stairs_constraint_example.png (100%) rename chapter_dynamic_programming/{intro_to_dynamic_programming.assets => dp_problem_features.assets}/climbing_stairs_constraint_state_transfer.png (100%) rename chapter_dynamic_programming/{intro_to_dynamic_programming.assets => dp_problem_features.assets}/min_cost_cs_dp.png (100%) rename chapter_dynamic_programming/{intro_to_dynamic_programming.assets => dp_problem_features.assets}/min_cost_cs_example.png (100%) create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step1.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step10.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step11.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step12.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step13.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step14.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step15.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step2.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step3.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step4.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step5.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step6.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step7.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step8.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_dp_step9.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_example.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/coin_change_ii_example.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step1.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step2.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step3.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step4.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step5.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step6.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem.assets/unbounded_knapsack_example.png create mode 100644 chapter_dynamic_programming/unbounded_knapsack_problem/index.html diff --git a/404.html b/404.html index 9c625c147..e23cd441a 100644 --- a/404.html +++ b/404.html @@ -1893,6 +1893,8 @@ + + @@ -1971,6 +1973,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_appendix/contribution/index.html b/chapter_appendix/contribution/index.html index 9e0e2ed47..321f879f4 100644 --- a/chapter_appendix/contribution/index.html +++ b/chapter_appendix/contribution/index.html @@ -1904,6 +1904,8 @@ + + @@ -1982,6 +1984,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_appendix/installation/index.html b/chapter_appendix/installation/index.html index d512c5496..6d25020ff 100644 --- a/chapter_appendix/installation/index.html +++ b/chapter_appendix/installation/index.html @@ -15,7 +15,7 @@ - + @@ -1904,6 +1904,8 @@ + + @@ -1982,6 +1984,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + @@ -2437,7 +2453,7 @@ diff --git a/chapter_array_and_linkedlist/index.html b/chapter_array_and_linkedlist/index.html index 5fd01a021..be38e79e0 100644 --- a/chapter_array_and_linkedlist/index.html +++ b/chapter_array_and_linkedlist/index.html @@ -1906,6 +1906,8 @@ + + @@ -1984,6 +1986,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_array_and_linkedlist/linked_list/index.html b/chapter_array_and_linkedlist/linked_list/index.html index cc8a71245..006c295e9 100644 --- a/chapter_array_and_linkedlist/linked_list/index.html +++ b/chapter_array_and_linkedlist/linked_list/index.html @@ -1968,6 +1968,8 @@ + + @@ -2046,6 +2048,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_array_and_linkedlist/list/index.html b/chapter_array_and_linkedlist/list/index.html index fee0203b3..492dbfd5f 100644 --- a/chapter_array_and_linkedlist/list/index.html +++ b/chapter_array_and_linkedlist/list/index.html @@ -1954,6 +1954,8 @@ + + @@ -2032,6 +2034,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_array_and_linkedlist/summary/index.html b/chapter_array_and_linkedlist/summary/index.html index 48f6b6aa4..b32c4c7a1 100644 --- a/chapter_array_and_linkedlist/summary/index.html +++ b/chapter_array_and_linkedlist/summary/index.html @@ -1947,6 +1947,8 @@ + + @@ -2025,6 +2027,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_backtracking/backtracking_algorithm/index.html b/chapter_backtracking/backtracking_algorithm/index.html index 31a7d8069..5644c636d 100644 --- a/chapter_backtracking/backtracking_algorithm/index.html +++ b/chapter_backtracking/backtracking_algorithm/index.html @@ -1870,14 +1870,14 @@
  • - 12.1.5.   典型例题 + 12.1.5.   优势与局限性
  • - 12.1.6.   优势与局限性 + 12.1.6.   典型例题
  • @@ -1982,6 +1982,8 @@ + + @@ -2060,6 +2062,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + @@ -2236,14 +2252,14 @@
  • - 12.1.5.   典型例题 + 12.1.5.   优势与局限性
  • - 12.1.6.   优势与局限性 + 12.1.6.   典型例题
  • @@ -2273,7 +2289,7 @@

    12.1.   回溯算法

    「回溯算法 Backtracking Algorithm」是一种通过穷举来解决问题的方法,它的核心思想是从一个初始状态出发,暴力搜索所有可能的解决方案,当遇到正确的解则将其记录,直到找到解或者尝试了所有可能的选择都无法找到解为止。

    -

    回溯算法通常采用「深度优先搜索」来遍历解空间。在二叉树章节中,我们提到前序、中序和后序遍历都属于深度优先搜索。下面,我们将从前序遍历入手,逐步了解回溯算法的工作原理。

    +

    回溯算法通常采用「深度优先搜索」来遍历解空间。在二叉树章节中,我们提到前序、中序和后序遍历都属于深度优先搜索。接下来我们先用前序遍历构造一个回溯问题,逐步了解回溯算法的工作原理。

    例题一

    给定一个二叉树,搜索并记录所有值为 \(7\) 的节点,返回节点列表。

    @@ -3542,7 +3558,19 @@

    相较于基于前序遍历的实现代码,基于回溯算法框架的实现代码虽然显得啰嗦,但通用性更好。实际上,所有回溯问题都可以在该框架下解决。我们需要根据具体问题来定义 statechoices ,并实现框架中的各个方法。

    -

    12.1.5.   典型例题

    +

    12.1.5.   优势与局限性

    +

    回溯算法本质上是一种深度优先搜索算法,它尝试所有可能的解决方案直到找到满足条件的解。这种方法的优势在于它能够找到所有可能的解决方案,而且在合理的剪枝操作下,具有很高的效率。

    +

    然而,在处理大规模或者复杂问题时,回溯算法的运行效率可能难以接受

    + +

    即便如此,回溯算法仍然是某些搜索问题和约束满足问题的最佳解决方案。对于这些问题,由于无法预测哪些选择可生成有效的解,因此我们必须对所有可能的选择进行遍历。在这种情况下,关键是如何进行效率优化

    + +

    12.1.6.   典型例题

    搜索问题:这类问题的目标是找到满足特定条件的解决方案。

    请注意,回溯算法通常不是解决组合优化问题的最优方法。0-1 背包问题通常使用动态规划解决;旅行商是一个 NP-Hard 问题,常用解决方法有遗传算法和蚁群算法等;最大团问题是图轮中的一个经典 NP-Hard 问题,通常用贪心算法等启发式算法来解决。

    -

    12.1.6.   优势与局限性

    -

    回溯算法本质上是一种深度优先搜索算法,它尝试所有可能的解决方案直到找到满足条件的解。这种方法的优势在于它能够找到所有可能的解决方案,而且在合理的剪枝操作下,具有很高的效率。

    -

    然而,在处理大规模或者复杂问题时,回溯算法的运行效率可能难以接受。这是因为在最坏的情况下,回溯算法需要遍历解空间的所有可能解。例如,求解 \(n\) 皇后问题的时间复杂度可以达到 \(O(n!)\) 。回溯算法的空间复杂度也可能较高。因为在每一次递归调用时,都需要保存当前的状态(例如选择路径、用于剪枝的辅助变量等),对于深度很大的递归,空间需求可能会变得非常大。

    -

    即便如此,回溯算法仍然是某些搜索问题和约束满足问题的最佳解决方案。对于这些问题,由于我们无法预测哪些选择可生成有效的解,因此我们必须对所有可能的选择进行遍历。在这种情况下,关键是如何进行效率优化

    - diff --git a/chapter_backtracking/index.html b/chapter_backtracking/index.html index f00b72559..9208daf75 100644 --- a/chapter_backtracking/index.html +++ b/chapter_backtracking/index.html @@ -1906,6 +1906,8 @@ + + @@ -1984,6 +1986,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_backtracking/n_queens_problem/index.html b/chapter_backtracking/n_queens_problem/index.html index 7941d6a39..6b5469dde 100644 --- a/chapter_backtracking/n_queens_problem/index.html +++ b/chapter_backtracking/n_queens_problem/index.html @@ -1947,6 +1947,8 @@ + + @@ -2025,6 +2027,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_backtracking/permutations_problem/index.html b/chapter_backtracking/permutations_problem/index.html index 176bb343c..a2bb6d847 100644 --- a/chapter_backtracking/permutations_problem/index.html +++ b/chapter_backtracking/permutations_problem/index.html @@ -1961,6 +1961,8 @@ + + @@ -2039,6 +2041,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + @@ -2231,7 +2247,7 @@

    12.2.   全排列问题

    全排列问题是回溯算法的一个典型应用。它的定义是在给定一个集合(如一个数组或字符串)的情况下,找出这个集合中元素的所有可能的排列。

    -

    如下表所示,列举了几个示例数组和其对应的所有排列。

    +

    下表列举了几个示例数据,包括输入数组和对应的所有排列。

    @@ -2559,7 +2575,7 @@

    需要重点关注的是,我们引入了一个布尔型数组 selected ,它的长度与输入数组长度相等,其中 selected[i] 表示 choices[i] 是否已被选择。我们利用 selected 避免某个元素被重复选择,从而实现剪枝。

    -

    如下图所示,假设我们第一轮选择 1 ,第二轮选择 3 ,第三轮选择 2 ,则需要在第二轮剪掉元素 1 的分支,在第三轮剪掉元素 1, 3 的分支。从本质上理解,此剪枝操作可将搜索空间大小从 \(O(n^n)\) 降低至 \(O(n!)\)

    +

    如下图所示,假设我们第一轮选择 1 ,第二轮选择 3 ,第三轮选择 2 ,则需要在第二轮剪掉元素 1 的分支,在第三轮剪掉元素 1, 3 的分支。此剪枝操作可将搜索空间大小从 \(O(n^n)\) 降低至 \(O(n!)\)

    全排列剪枝示例

    Fig. 全排列剪枝示例

    @@ -2572,7 +2588,7 @@

    重复排列

    Fig. 重复排列

    -

    那么,如何去除重复的排列呢?最直接地,我们可以借助一个哈希表,直接对排列结果进行去重。然而,这样做不够优雅,因为生成重复排列的搜索分支是没有必要的,应当被提前识别并剪枝,这样可以提升算法效率。

    +

    那么,如何去除重复的排列呢?最直接地,我们可以借助一个哈希表,直接对排列结果进行去重。然而这样做不够优雅,因为生成重复排列的搜索分支是没有必要的,应当被提前识别并剪枝,这样可以进一步提升算法效率。

    观察发现,在第一轮中,选择 \(1\) 或选择 \(\hat{1}\) 是等价的,因为在这两个选择之下生成的所有排列都是重复的。因此,我们应该把 \(\hat{1}\) 剪枝掉。同理,在第一轮选择 \(2\) 后,第二轮选择中的 \(1\)\(\hat{1}\) 也会产生重复分支,因此也需要将第二轮的 \(\hat{1}\) 剪枝。

    重复排列剪枝

    Fig. 重复排列剪枝

    diff --git a/chapter_backtracking/subset_sum_problem/index.html b/chapter_backtracking/subset_sum_problem/index.html index a4ef111fc..fb4cb1dc6 100644 --- a/chapter_backtracking/subset_sum_problem/index.html +++ b/chapter_backtracking/subset_sum_problem/index.html @@ -1961,6 +1961,8 @@ + + @@ -2039,6 +2041,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_backtracking/summary/index.html b/chapter_backtracking/summary/index.html index 19c037311..c93817fc2 100644 --- a/chapter_backtracking/summary/index.html +++ b/chapter_backtracking/summary/index.html @@ -1916,6 +1916,8 @@ + + @@ -1994,6 +1996,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_computational_complexity/index.html b/chapter_computational_complexity/index.html index d0bd57385..e582aa6b7 100644 --- a/chapter_computational_complexity/index.html +++ b/chapter_computational_complexity/index.html @@ -1906,6 +1906,8 @@ + + @@ -1984,6 +1986,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_computational_complexity/performance_evaluation/index.html b/chapter_computational_complexity/performance_evaluation/index.html index 184269773..1abde9866 100644 --- a/chapter_computational_complexity/performance_evaluation/index.html +++ b/chapter_computational_complexity/performance_evaluation/index.html @@ -1981,6 +1981,8 @@ + + @@ -2059,6 +2061,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_computational_complexity/space_complexity/index.html b/chapter_computational_complexity/space_complexity/index.html index 74ebb1f49..2f44af78f 100644 --- a/chapter_computational_complexity/space_complexity/index.html +++ b/chapter_computational_complexity/space_complexity/index.html @@ -2009,6 +2009,8 @@ + + @@ -2087,6 +2089,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_computational_complexity/summary/index.html b/chapter_computational_complexity/summary/index.html index 1304ea5ba..60a06e7d9 100644 --- a/chapter_computational_complexity/summary/index.html +++ b/chapter_computational_complexity/summary/index.html @@ -1947,6 +1947,8 @@ + + @@ -2025,6 +2027,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_computational_complexity/time_complexity/index.html b/chapter_computational_complexity/time_complexity/index.html index 35a4769a5..3b4b4e8d7 100644 --- a/chapter_computational_complexity/time_complexity/index.html +++ b/chapter_computational_complexity/time_complexity/index.html @@ -2057,6 +2057,8 @@ + + @@ -2135,6 +2137,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_data_structure/basic_data_types/index.html b/chapter_data_structure/basic_data_types/index.html index 4c082ef18..e942ec164 100644 --- a/chapter_data_structure/basic_data_types/index.html +++ b/chapter_data_structure/basic_data_types/index.html @@ -1916,6 +1916,8 @@ + + @@ -1994,6 +1996,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + @@ -2260,7 +2276,7 @@
    -
    /* 使用多种「基本数据类型」来初始化「数组」 */
    +
    // 使用多种基本数据类型来初始化数组
     int[] numbers = new int[5];
     float[] decimals = new float[5];
     char[] characters = new char[5];
    @@ -2268,7 +2284,7 @@
     
    -
    /* 使用多种「基本数据类型」来初始化「数组」 */
    +
    // 使用多种基本数据类型来初始化数组
     int numbers[5];
     float decimals[5];
     char characters[5];
    @@ -2289,19 +2305,19 @@
     
    -
    /* JavaScript 的数组可以自由存储各种基本数据类型和对象 */
    +
    // JavaScript 的数组可以自由存储各种基本数据类型和对象
     const array = [0, 0.0, 'a', false];
     
    -
    /* 使用多种「基本数据类型」来初始化「数组」 */
    +
    // 使用多种基本数据类型来初始化数组
     const numbers: number[] = [];
     const characters: string[] = [];
     const booleans: boolean[] = [];
     
    -
    /* 使用多种「基本数据类型」来初始化「数组」 */
    +
    // 使用多种基本数据类型来初始化数组
     int numbers[10];
     float decimals[10];
     char characters[10];
    @@ -2309,7 +2325,7 @@
     
    -
    /* 使用多种「基本数据类型」来初始化「数组」 */
    +
    // 使用多种基本数据类型来初始化数组
     int[] numbers = new int[5];
     float[] decimals = new float[5];
     char[] characters = new char[5];
    @@ -2317,7 +2333,7 @@
     
    -
    /* 使用多种「基本数据类型」来初始化「数组」 */
    +
    // 使用多种基本数据类型来初始化数组
     let numbers = Array(repeating: Int(), count: 5)
     let decimals = Array(repeating: Double(), count: 5)
     let characters = Array(repeating: Character("a"), count: 5)
    @@ -2329,7 +2345,7 @@
     
    -
    /* 使用多种「基本数据类型」来初始化「数组」 */
    +
    // 使用多种基本数据类型来初始化数组
     List<int> numbers = List.filled(5, 0);
     List<double> decimals = List.filled(5, 0.0);
     List<String> characters = List.filled(5, 'a');
    diff --git a/chapter_data_structure/character_encoding/index.html b/chapter_data_structure/character_encoding/index.html
    index 79e66e809..94d777c21 100644
    --- a/chapter_data_structure/character_encoding/index.html
    +++ b/chapter_data_structure/character_encoding/index.html
    @@ -1975,6 +1975,8 @@
             
               
             
    +          
    +        
           
           
             
    @@ -2053,6 +2055,20 @@
     
                 
               
    +            
    +              
    +  
    +  
    +  
    +    
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_data_structure/classification_of_data_structure/index.html b/chapter_data_structure/classification_of_data_structure/index.html index fff502479..3a6dc4b54 100644 --- a/chapter_data_structure/classification_of_data_structure/index.html +++ b/chapter_data_structure/classification_of_data_structure/index.html @@ -1954,6 +1954,8 @@ + + @@ -2032,6 +2034,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + @@ -2219,16 +2235,22 @@

    数据结构可以从逻辑结构和物理结构两个维度进行分类。

    3.1.1.   逻辑结构:线性与非线性

    「逻辑结构」揭示了数据元素之间的逻辑关系。在数组和链表中,数据按照顺序依次排列,体现了数据之间的线性关系;而在树中,数据从顶部向下按层次排列,表现出祖先与后代之间的派生关系;图则由节点和边构成,反映了复杂的网络关系。

    -

    逻辑结构通常分为「线性」和「非线性」两类。线性结构比较直观,指数据在逻辑关系上呈线性排列;非线性结构则相反,呈非线性排列,例如网状或树状结构。

    +

    逻辑结构通常分为“线性”和“非线性”两类。线性结构比较直观,指数据在逻辑关系上呈线性排列;非线性结构则相反,呈非线性排列。

    • 线性数据结构:数组、链表、栈、队列、哈希表;
    • -
    • 非线性数据结构:树、图、堆、哈希表;
    • +
    • 非线性数据结构:树、堆、图、哈希表;

    线性与非线性数据结构

    Fig. 线性与非线性数据结构

    +

    非线性数据结构可以进一步被划分为树形结构和网状结构。

    +
      +
    • 线性结构:数组、链表、队列、栈、哈希表,元素存在一对一的顺序关系;
    • +
    • 树形结构:树、堆、哈希表,元素存在一对多的关系;
    • +
    • 网状结构:图,元素存在多对多的关系;
    • +

    3.1.2.   物理结构:连续与离散

    -

    在计算机中,内存和硬盘是两种主要的存储硬件设备。「硬盘」主要用于长期存储数据,容量较大(通常可达到 TB 级别)、速度较慢。「内存」用于运行程序时暂存数据,速度较快,但容量较小(通常为 GB 级别)。

    +

    在计算机中,内存和硬盘是两种主要的存储硬件设备。硬盘主要用于长期存储数据,容量较大(通常可达到 TB 级别)、速度较慢。内存用于运行程序时暂存数据,速度较快,但容量较小(通常为 GB 级别)。

    在算法运行过程中,相关数据都存储在内存中。下图展示了一个计算机内存条,其中每个黑色方块都包含一块内存空间。我们可以将内存想象成一个巨大的 Excel 表格,其中每个单元格都可以存储 1 byte 的数据,在算法运行时,所有数据都被存储在这些单元格中。

    系统通过「内存地址 Memory Location」来访问目标内存位置的数据。计算机根据特定规则为表格中的每个单元格分配编号,确保每个内存空间都有唯一的内存地址。有了这些地址,程序便可以访问内存中的数据。

    内存条、内存空间、内存地址

    @@ -2244,7 +2266,7 @@
  • 基于数组可实现:栈、队列、哈希表、树、堆、图、矩阵、张量(维度 \(\geq 3\) 的数组)等;
  • 基于链表可实现:栈、队列、哈希表、树、堆、图等;
  • -

    基于数组实现的数据结构也被称为「静态数据结构」,这意味着此类数据结构在初始化后长度不可变。相对应地,基于链表实现的数据结构被称为「动态数据结构」,这类数据结构在初始化后,仍可以在程序运行过程中对其长度进行调整。

    +

    基于数组实现的数据结构也被称为“静态数据结构”,这意味着此类数据结构在初始化后长度不可变。相对应地,基于链表实现的数据结构被称为“动态数据结构”,这类数据结构在初始化后,仍可以在程序运行过程中对其长度进行调整。

    Tip

    如若感觉理解物理结构有困难,建议先阅读下一章“数组与链表”,然后再回头理解物理结构的含义。数组与链表是其他所有数据结构的基石,建议你投入更多时间深入了解这两种基本数据结构。

    diff --git a/chapter_data_structure/index.html b/chapter_data_structure/index.html index fbcf41913..f054b9034 100644 --- a/chapter_data_structure/index.html +++ b/chapter_data_structure/index.html @@ -1906,6 +1906,8 @@ + + @@ -1984,6 +1986,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_data_structure/number_encoding/index.html b/chapter_data_structure/number_encoding/index.html index 09e25d9eb..0080f67f9 100644 --- a/chapter_data_structure/number_encoding/index.html +++ b/chapter_data_structure/number_encoding/index.html @@ -1954,6 +1954,8 @@ + + @@ -2032,6 +2034,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_data_structure/summary/index.html b/chapter_data_structure/summary/index.html index 88788acc7..7b592b0b9 100644 --- a/chapter_data_structure/summary/index.html +++ b/chapter_data_structure/summary/index.html @@ -1947,6 +1947,8 @@ + + @@ -2025,6 +2027,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_constraint_example.png b/chapter_dynamic_programming/dp_problem_features.assets/climbing_stairs_constraint_example.png similarity index 100% rename from chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_constraint_example.png rename to chapter_dynamic_programming/dp_problem_features.assets/climbing_stairs_constraint_example.png diff --git a/chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_constraint_state_transfer.png b/chapter_dynamic_programming/dp_problem_features.assets/climbing_stairs_constraint_state_transfer.png similarity index 100% rename from chapter_dynamic_programming/intro_to_dynamic_programming.assets/climbing_stairs_constraint_state_transfer.png rename to chapter_dynamic_programming/dp_problem_features.assets/climbing_stairs_constraint_state_transfer.png diff --git a/chapter_dynamic_programming/intro_to_dynamic_programming.assets/min_cost_cs_dp.png b/chapter_dynamic_programming/dp_problem_features.assets/min_cost_cs_dp.png similarity index 100% rename from chapter_dynamic_programming/intro_to_dynamic_programming.assets/min_cost_cs_dp.png rename to chapter_dynamic_programming/dp_problem_features.assets/min_cost_cs_dp.png diff --git a/chapter_dynamic_programming/intro_to_dynamic_programming.assets/min_cost_cs_example.png b/chapter_dynamic_programming/dp_problem_features.assets/min_cost_cs_example.png similarity index 100% rename from chapter_dynamic_programming/intro_to_dynamic_programming.assets/min_cost_cs_example.png rename to chapter_dynamic_programming/dp_problem_features.assets/min_cost_cs_example.png diff --git a/chapter_dynamic_programming/dp_problem_features/index.html b/chapter_dynamic_programming/dp_problem_features/index.html index ad27cade8..7e072eaca 100644 --- a/chapter_dynamic_programming/dp_problem_features/index.html +++ b/chapter_dynamic_programming/dp_problem_features/index.html @@ -1906,6 +1906,8 @@ + + @@ -2032,6 +2034,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + @@ -2225,7 +2241,7 @@

    给定一个楼梯,你每步可以上 \(1\) 阶或者 \(2\) 阶,每一阶楼梯上都贴有一个非负整数,表示你在该台阶所需要付出的代价。给定一个非负整数数组 \(cost\) ,其中 \(cost[i]\) 表示在第 \(i\) 个台阶需要付出的代价,\(cost[0]\) 为地面起始点。请计算最少需要付出多少代价才能到达顶部?

    如下图所示,若第 \(1\) , \(2\) , \(3\) 阶的代价分别为 \(1\) , \(10\) , \(1\) ,则从地面爬到第 \(3\) 阶的最小代价为 \(2\)

    -

    爬到第 3 阶的最小代价

    +

    爬到第 3 阶的最小代价

    Fig. 爬到第 3 阶的最小代价

    \(dp[i]\) 为爬到第 \(i\) 阶累计付出的代价,由于第 \(i\) 阶只可能从 \(i - 1\) 阶或 \(i - 2\) 阶走来,因此 \(dp[i]\) 只可能等于 \(dp[i - 1] + cost[i]\)\(dp[i - 2] + cost[i]\) 。为了尽可能减少代价,我们应该选择两者中较小的那一个,即:

    @@ -2341,7 +2357,7 @@ dp[i] = \min(dp[i-1], dp[i-2]) + cost[i]
    -

    爬楼梯最小代价的动态规划过程

    +

    爬楼梯最小代价的动态规划过程

    Fig. 爬楼梯最小代价的动态规划过程

    这道题同样也可以进行状态压缩,将一维压缩至零维,使得空间复杂度从 \(O(n)\) 降低至 \(O(1)\)

    @@ -2446,7 +2462,7 @@ dp[i] = \min(dp[i-1], dp[i-2]) + cost[i]

    给定一个共有 \(n\) 阶的楼梯,你每步可以上 \(1\) 阶或者 \(2\) 阶,但不能连续两轮跳 \(1\),请问有多少种方案可以爬到楼顶。

    例如,爬上第 \(3\) 阶仅剩 \(2\) 种可行方案,其中连续三次跳 \(1\) 阶的方案不满足约束条件,因此被舍弃。

    -

    带约束爬到第 3 阶的方案数量

    +

    带约束爬到第 3 阶的方案数量

    Fig. 带约束爬到第 3 阶的方案数量

    在该问题中,下一步选择不能由当前状态(当前楼梯阶数)独立决定,还和前一个状态(上轮楼梯阶数)有关。如果上一轮是跳 \(1\) 阶上来的,那么下一轮就必须跳 \(2\) 阶。

    @@ -2463,7 +2479,7 @@ dp[i, 1] = dp[i-1, 2] \\ dp[i, 2] = dp[i-2, 1] + dp[i-2, 2] \end{cases} \]
    -

    考虑约束下的递推关系

    +

    考虑约束下的递推关系

    Fig. 考虑约束下的递推关系

    最终,返回 \(dp[n, 1] + dp[n, 2]\) 即可,两者之和代表爬到第 \(n\) 阶的方案总数。

    diff --git a/chapter_dynamic_programming/dp_solution_pipeline/index.html b/chapter_dynamic_programming/dp_solution_pipeline/index.html index a26945410..676ce6d03 100644 --- a/chapter_dynamic_programming/dp_solution_pipeline/index.html +++ b/chapter_dynamic_programming/dp_solution_pipeline/index.html @@ -1906,6 +1906,8 @@ + + @@ -2053,6 +2055,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + @@ -2325,12 +2341,12 @@ dp[i, j] = \min(dp[i-1, j], dp[i, j-1]) + grid[i, j]

    Note

    边界条件即初始状态,在搜索中用于剪枝,在动态规划中用于初始化 \(dp\) 表。状态转移顺序的核心是要保证在计算当前问题时,所有它依赖的更小子问题都已经被正确地计算出来。

    -

    最后,我们基于以上结果实现解法即可。熟练度较高同学可以直接写出动态规划解法,初学者可以按照“暴力搜索 \(\rightarrow\) 记忆化搜索 \(\rightarrow\) 动态规划” 的顺序实现。

    +

    接下来,我们就可以实现动态规划代码了。然而,由于子问题分解是一种从顶至底的思想,因此按照“暴力搜索 \(\rightarrow\) 记忆化搜索 \(\rightarrow\) 动态规划”的顺序实现更加符合思维习惯。

    13.3.3.   方法一:暴力搜索

    从状态 \([i, j]\) 开始搜索,不断分解为更小的状态 \([i-1, j]\)\([i, j-1]\) ,包括以下递归要素:

    • 递归参数:状态 \([i, j]\)返回值:从 \([0, 0]\)\([i, j]\) 的最小路径和 \(dp[i, j]\)
    • -
    • 终止条件:当 \(i = 0\)\(j = 0\) 时,返回代价 \(grid[0][0]\)
    • +
    • 终止条件:当 \(i = 0\)\(j = 0\) 时,返回代价 \(grid[0, 0]\)
    • 剪枝:当 \(i < 0\) 时或 \(j < 0\) 时索引越界,此时返回代价 \(+\infty\) ,代表不可行;
    diff --git a/chapter_dynamic_programming/index.html b/chapter_dynamic_programming/index.html index 43dfd9e59..bc208e670 100644 --- a/chapter_dynamic_programming/index.html +++ b/chapter_dynamic_programming/index.html @@ -1906,6 +1906,8 @@ + + @@ -1984,6 +1986,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_dynamic_programming/intro_to_dynamic_programming/index.html b/chapter_dynamic_programming/intro_to_dynamic_programming/index.html index 46b998154..8dee22181 100644 --- a/chapter_dynamic_programming/intro_to_dynamic_programming/index.html +++ b/chapter_dynamic_programming/intro_to_dynamic_programming/index.html @@ -1906,6 +1906,8 @@ + + @@ -2039,6 +2041,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + diff --git a/chapter_dynamic_programming/knapsack_problem/index.html b/chapter_dynamic_programming/knapsack_problem/index.html index 47e2a3424..f19a52170 100644 --- a/chapter_dynamic_programming/knapsack_problem/index.html +++ b/chapter_dynamic_programming/knapsack_problem/index.html @@ -18,7 +18,7 @@ - + @@ -1906,6 +1906,8 @@ + + @@ -2039,6 +2041,20 @@ + + + + + +
  • + + 13.5.   完全背包问题(New) + +
  • + + + + @@ -2245,7 +2261,7 @@

    第一步:思考每轮的决策,定义状态,从而得到 \(dp\)

    在 0-1 背包问题中,不放入背包,背包容量不变;放入背包,背包容量减小。由此可得状态定义:当前物品编号 \(i\) 和剩余背包容量 \(c\) ,记为 \([i, c]\)

    状态 \([i, c]\) 对应的子问题为:\(i\) 个物品在剩余容量为 \(c\) 的背包中的最大价值,记为 \(dp[i, c]\)

    -

    至此,我们得到一个尺寸为 \(n \times cap\) 的二维 \(dp\) 矩阵。

    +

    需要求解的是 \(dp[n, cap]\) ,因此需要一个尺寸为 \((n+1) \times (cap+1)\) 的二维 \(dp\) 表。

    第二步:找出最优子结构,进而推导出状态转移方程

    当我们做出物品 \(i\) 的决策后,剩余的是前 \(i-1\) 个物品的决策。因此,状态转移分为两种情况:

      @@ -2260,6 +2276,10 @@ dp[i, c] = \max(dp[i-1, c], dp[i-1, c - wgt[i-1]] + val[i-1])

      第三步:确定边界条件和状态转移顺序

      当无物品或无剩余背包容量时最大价值为 \(0\) ,即所有 \(dp[i, 0]\)\(dp[0, c]\) 都等于 \(0\)

      当前状态 \([i, c]\) 从上方的状态 \([i-1, c]\) 和左上方的状态 \([i-1, c-wgt[i-1]]\) 转移而来,因此通过两层循环正序遍历整个 \(dp\) 表即可。

      +
      +

      Tip

      +

      完成以上三步后,我们可以直接实现从底至顶的动态规划解法。而为了展示本题包含的重叠子问题,本文也同时给出从顶至底的暴力搜索和记忆化搜索解法。

      +

      13.4.1.   方法一:暴力搜索

      搜索代码包含以下要素:

        @@ -2510,7 +2530,7 @@ dp[i, c] = \max(dp[i-1, c], dp[i-1, c - wgt[i-1]] + val[i-1])

        Fig. 0-1 背包的记忆化搜索递归树

        13.4.3.   方法三:动态规划

        -

        动态规划解法本质上就是在状态转移中填充 dp 矩阵的过程,代码如下所示。

        +

        动态规划解法本质上就是在状态转移中填充 \(dp\) 表的过程,代码如下所示。

        @@ -2627,7 +2647,7 @@ dp[i, c] = \max(dp[i-1, c], dp[i-1, c - wgt[i-1]] + val[i-1])
        -

        如下图所示,时间复杂度由 dp 矩阵大小决定,为 \(O(n \times cap)\)

        +

        如下图所示,时间复杂度由数组 dp 大小决定,为 \(O(n \times cap)\)

        @@ -2674,8 +2694,8 @@ dp[i, c] = \max(dp[i-1, c], dp[i-1, c - wgt[i-1]] + val[i-1])
        -

        最后考虑状态压缩。以上代码中的 dp 矩阵占用 \(O(n \times cap)\) 空间。由于每个状态都只与其上一行的状态有关,因此我们可以使用两个数组滚动前进,将空间复杂度从 \(O(n^2)\) 将低至 \(O(n)\) 。代码省略,有兴趣的同学可以自行实现。

        -

        那么,我们是否可以仅用一个数组实现状态压缩呢?观察可知,每个状态都是由左上方或正上方的格子转移过来的。假设只有一个数组,当遍历到第 \(i\) 行时,该数组存储的仍然是第 \(i-1\) 行的状态,为了避免左边区域的格子在状态转移中被覆盖,我们应采取倒序遍历。

        +

        最后考虑状态压缩。以上代码中的数组 dp 占用 \(O(n \times cap)\) 空间。由于每个状态都只与其上一行的状态有关,因此我们可以使用两个数组滚动前进,将空间复杂度从 \(O(n^2)\) 将低至 \(O(n)\) 。代码省略,有兴趣的同学可以自行实现。

        +

        那么,我们是否可以仅用一个数组实现状态压缩呢?观察可知,每个状态都是由左上方或正上方的格子转移过来的。假设只有一个数组,当遍历到第 \(i\) 行时,该数组存储的仍然是第 \(i-1\) 行的状态,为了避免左方区域的格子在状态转移中被覆盖,应该采取倒序遍历

        以下动画展示了在单个数组下从第 \(i=1\) 行转换至第 \(i=2\) 行的过程。建议你思考一下正序遍历和倒序遍历的区别。

        @@ -2699,7 +2719,7 @@ dp[i, c] = \max(dp[i-1, c], dp[i-1, c - wgt[i-1]] + val[i-1])
    -

    如以下代码所示,我们仅需将 dp 矩阵的第一维 \(i\) 直接删除,并且将内循环修改为倒序遍历即可。

    +

    如以下代码所示,我们仅需将数组 dp 的第一维 \(i\) 直接删除,并且将内循环修改为倒序遍历即可。

    @@ -2907,13 +2927,13 @@ dp[i, c] = \max(dp[i-1, c], dp[i-1, c - wgt[i-1]] + val[i-1]) -