Sort the coding languages by applications. (#721)

This commit is contained in:
Yudong Jin
2023-09-04 03:19:08 +08:00
committed by GitHub
parent 8d5e84f70a
commit 9c3b7b6422
55 changed files with 6826 additions and 6826 deletions

View File

@@ -34,10 +34,10 @@ $$
根据状态转移方程,以及初始状态 $dp[1] = cost[1]$ 和 $dp[2] = cost[2]$ ,我们就可以得到动态规划代码。
=== "Java"
=== "Python"
```java title="min_cost_climbing_stairs_dp.java"
[class]{min_cost_climbing_stairs_dp}-[func]{minCostClimbingStairsDP}
```python title="min_cost_climbing_stairs_dp.py"
[class]{}-[func]{min_cost_climbing_stairs_dp}
```
=== "C++"
@@ -46,10 +46,16 @@ $$
[class]{}-[func]{minCostClimbingStairsDP}
```
=== "Python"
=== "Java"
```python title="min_cost_climbing_stairs_dp.py"
[class]{}-[func]{min_cost_climbing_stairs_dp}
```java title="min_cost_climbing_stairs_dp.java"
[class]{min_cost_climbing_stairs_dp}-[func]{minCostClimbingStairsDP}
```
=== "C#"
```csharp title="min_cost_climbing_stairs_dp.cs"
[class]{min_cost_climbing_stairs_dp}-[func]{minCostClimbingStairsDP}
```
=== "Go"
@@ -58,6 +64,12 @@ $$
[class]{}-[func]{minCostClimbingStairsDP}
```
=== "Swift"
```swift title="min_cost_climbing_stairs_dp.swift"
[class]{}-[func]{minCostClimbingStairsDP}
```
=== "JS"
```javascript title="min_cost_climbing_stairs_dp.js"
@@ -70,30 +82,6 @@ $$
[class]{}-[func]{minCostClimbingStairsDP}
```
=== "C"
```c title="min_cost_climbing_stairs_dp.c"
[class]{}-[func]{minCostClimbingStairsDP}
```
=== "C#"
```csharp title="min_cost_climbing_stairs_dp.cs"
[class]{min_cost_climbing_stairs_dp}-[func]{minCostClimbingStairsDP}
```
=== "Swift"
```swift title="min_cost_climbing_stairs_dp.swift"
[class]{}-[func]{minCostClimbingStairsDP}
```
=== "Zig"
```zig title="min_cost_climbing_stairs_dp.zig"
[class]{}-[func]{minCostClimbingStairsDP}
```
=== "Dart"
```dart title="min_cost_climbing_stairs_dp.dart"
@@ -106,16 +94,28 @@ $$
[class]{}-[func]{min_cost_climbing_stairs_dp}
```
=== "C"
```c title="min_cost_climbing_stairs_dp.c"
[class]{}-[func]{minCostClimbingStairsDP}
```
=== "Zig"
```zig title="min_cost_climbing_stairs_dp.zig"
[class]{}-[func]{minCostClimbingStairsDP}
```
下图展示了以上代码的动态规划过程。
![爬楼梯最小代价的动态规划过程](dp_problem_features.assets/min_cost_cs_dp.png)
本题也可以进行空间优化,将一维压缩至零维,使得空间复杂度从 $O(n)$ 降低至 $O(1)$ 。
=== "Java"
=== "Python"
```java title="min_cost_climbing_stairs_dp.java"
[class]{min_cost_climbing_stairs_dp}-[func]{minCostClimbingStairsDPComp}
```python title="min_cost_climbing_stairs_dp.py"
[class]{}-[func]{min_cost_climbing_stairs_dp_comp}
```
=== "C++"
@@ -124,10 +124,16 @@ $$
[class]{}-[func]{minCostClimbingStairsDPComp}
```
=== "Python"
=== "Java"
```python title="min_cost_climbing_stairs_dp.py"
[class]{}-[func]{min_cost_climbing_stairs_dp_comp}
```java title="min_cost_climbing_stairs_dp.java"
[class]{min_cost_climbing_stairs_dp}-[func]{minCostClimbingStairsDPComp}
```
=== "C#"
```csharp title="min_cost_climbing_stairs_dp.cs"
[class]{min_cost_climbing_stairs_dp}-[func]{minCostClimbingStairsDPComp}
```
=== "Go"
@@ -136,6 +142,12 @@ $$
[class]{}-[func]{minCostClimbingStairsDPComp}
```
=== "Swift"
```swift title="min_cost_climbing_stairs_dp.swift"
[class]{}-[func]{minCostClimbingStairsDPComp}
```
=== "JS"
```javascript title="min_cost_climbing_stairs_dp.js"
@@ -148,30 +160,6 @@ $$
[class]{}-[func]{minCostClimbingStairsDPComp}
```
=== "C"
```c title="min_cost_climbing_stairs_dp.c"
[class]{}-[func]{minCostClimbingStairsDPComp}
```
=== "C#"
```csharp title="min_cost_climbing_stairs_dp.cs"
[class]{min_cost_climbing_stairs_dp}-[func]{minCostClimbingStairsDPComp}
```
=== "Swift"
```swift title="min_cost_climbing_stairs_dp.swift"
[class]{}-[func]{minCostClimbingStairsDPComp}
```
=== "Zig"
```zig title="min_cost_climbing_stairs_dp.zig"
[class]{}-[func]{minCostClimbingStairsDPComp}
```
=== "Dart"
```dart title="min_cost_climbing_stairs_dp.dart"
@@ -184,6 +172,18 @@ $$
[class]{}-[func]{min_cost_climbing_stairs_dp_comp}
```
=== "C"
```c title="min_cost_climbing_stairs_dp.c"
[class]{}-[func]{minCostClimbingStairsDPComp}
```
=== "Zig"
```zig title="min_cost_climbing_stairs_dp.zig"
[class]{}-[func]{minCostClimbingStairsDPComp}
```
## 无后效性
无后效性是动态规划能够有效解决问题的重要特性之一,定义为:**给定一个确定的状态,它的未来发展只与当前状态有关,而与当前状态过去所经历过的所有状态无关**。
@@ -222,10 +222,10 @@ $$
最终,返回 $dp[n, 1] + dp[n, 2]$ 即可,两者之和代表爬到第 $n$ 阶的方案总数。
=== "Java"
=== "Python"
```java title="climbing_stairs_constraint_dp.java"
[class]{climbing_stairs_constraint_dp}-[func]{climbingStairsConstraintDP}
```python title="climbing_stairs_constraint_dp.py"
[class]{}-[func]{climbing_stairs_constraint_dp}
```
=== "C++"
@@ -234,10 +234,16 @@ $$
[class]{}-[func]{climbingStairsConstraintDP}
```
=== "Python"
=== "Java"
```python title="climbing_stairs_constraint_dp.py"
[class]{}-[func]{climbing_stairs_constraint_dp}
```java title="climbing_stairs_constraint_dp.java"
[class]{climbing_stairs_constraint_dp}-[func]{climbingStairsConstraintDP}
```
=== "C#"
```csharp title="climbing_stairs_constraint_dp.cs"
[class]{climbing_stairs_constraint_dp}-[func]{climbingStairsConstraintDP}
```
=== "Go"
@@ -246,6 +252,12 @@ $$
[class]{}-[func]{climbingStairsConstraintDP}
```
=== "Swift"
```swift title="climbing_stairs_constraint_dp.swift"
[class]{}-[func]{climbingStairsConstraintDP}
```
=== "JS"
```javascript title="climbing_stairs_constraint_dp.js"
@@ -258,30 +270,6 @@ $$
[class]{}-[func]{climbingStairsConstraintDP}
```
=== "C"
```c title="climbing_stairs_constraint_dp.c"
[class]{}-[func]{climbingStairsConstraintDP}
```
=== "C#"
```csharp title="climbing_stairs_constraint_dp.cs"
[class]{climbing_stairs_constraint_dp}-[func]{climbingStairsConstraintDP}
```
=== "Swift"
```swift title="climbing_stairs_constraint_dp.swift"
[class]{}-[func]{climbingStairsConstraintDP}
```
=== "Zig"
```zig title="climbing_stairs_constraint_dp.zig"
[class]{}-[func]{climbingStairsConstraintDP}
```
=== "Dart"
```dart title="climbing_stairs_constraint_dp.dart"
@@ -294,6 +282,18 @@ $$
[class]{}-[func]{climbing_stairs_constraint_dp}
```
=== "C"
```c title="climbing_stairs_constraint_dp.c"
[class]{}-[func]{climbingStairsConstraintDP}
```
=== "Zig"
```zig title="climbing_stairs_constraint_dp.zig"
[class]{}-[func]{climbingStairsConstraintDP}
```
在上面的案例中,由于仅需多考虑前面一个状态,我们仍然可以通过扩展状态定义,使得问题重新满足无后效性。然而,某些问题具有非常严重的“有后效性”。
!!! question "爬楼梯与障碍生成"

View File

@@ -98,10 +98,10 @@ $$
- **终止条件**:当 $i = 0$ 且 $j = 0$ 时,返回代价 $grid[0, 0]$ 。
- **剪枝**:当 $i < 0$ 时或 $j < 0$ 时索引越界,此时返回代价 $+\infty$ ,代表不可行。
=== "Java"
=== "Python"
```java title="min_path_sum.java"
[class]{min_path_sum}-[func]{minPathSumDFS}
```python title="min_path_sum.py"
[class]{}-[func]{min_path_sum_dfs}
```
=== "C++"
@@ -110,10 +110,16 @@ $$
[class]{}-[func]{minPathSumDFS}
```
=== "Python"
=== "Java"
```python title="min_path_sum.py"
[class]{}-[func]{min_path_sum_dfs}
```java title="min_path_sum.java"
[class]{min_path_sum}-[func]{minPathSumDFS}
```
=== "C#"
```csharp title="min_path_sum.cs"
[class]{min_path_sum}-[func]{minPathSumDFS}
```
=== "Go"
@@ -122,6 +128,12 @@ $$
[class]{}-[func]{minPathSumDFS}
```
=== "Swift"
```swift title="min_path_sum.swift"
[class]{}-[func]{minPathSumDFS}
```
=== "JS"
```javascript title="min_path_sum.js"
@@ -134,30 +146,6 @@ $$
[class]{}-[func]{minPathSumDFS}
```
=== "C"
```c title="min_path_sum.c"
[class]{}-[func]{minPathSumDFS}
```
=== "C#"
```csharp title="min_path_sum.cs"
[class]{min_path_sum}-[func]{minPathSumDFS}
```
=== "Swift"
```swift title="min_path_sum.swift"
[class]{}-[func]{minPathSumDFS}
```
=== "Zig"
```zig title="min_path_sum.zig"
[class]{}-[func]{minPathSumDFS}
```
=== "Dart"
```dart title="min_path_sum.dart"
@@ -170,6 +158,18 @@ $$
[class]{}-[func]{min_path_sum_dfs}
```
=== "C"
```c title="min_path_sum.c"
[class]{}-[func]{minPathSumDFS}
```
=== "Zig"
```zig title="min_path_sum.zig"
[class]{}-[func]{minPathSumDFS}
```
下图给出了以 $dp[2, 1]$ 为根节点的递归树,其中包含一些重叠子问题,其数量会随着网格 `grid` 的尺寸变大而急剧增多。
本质上看,造成重叠子问题的原因为:**存在多条路径可以从左上角到达某一单元格**。
@@ -182,10 +182,10 @@ $$
我们引入一个和网格 `grid` 相同尺寸的记忆列表 `mem` ,用于记录各个子问题的解,并将重叠子问题进行剪枝。
=== "Java"
=== "Python"
```java title="min_path_sum.java"
[class]{min_path_sum}-[func]{minPathSumDFSMem}
```python title="min_path_sum.py"
[class]{}-[func]{min_path_sum_dfs_mem}
```
=== "C++"
@@ -194,10 +194,16 @@ $$
[class]{}-[func]{minPathSumDFSMem}
```
=== "Python"
=== "Java"
```python title="min_path_sum.py"
[class]{}-[func]{min_path_sum_dfs_mem}
```java title="min_path_sum.java"
[class]{min_path_sum}-[func]{minPathSumDFSMem}
```
=== "C#"
```csharp title="min_path_sum.cs"
[class]{min_path_sum}-[func]{minPathSumDFSMem}
```
=== "Go"
@@ -206,6 +212,12 @@ $$
[class]{}-[func]{minPathSumDFSMem}
```
=== "Swift"
```swift title="min_path_sum.swift"
[class]{}-[func]{minPathSumDFSMem}
```
=== "JS"
```javascript title="min_path_sum.js"
@@ -218,30 +230,6 @@ $$
[class]{}-[func]{minPathSumDFSMem}
```
=== "C"
```c title="min_path_sum.c"
[class]{}-[func]{minPathSumDFSMem}
```
=== "C#"
```csharp title="min_path_sum.cs"
[class]{min_path_sum}-[func]{minPathSumDFSMem}
```
=== "Swift"
```swift title="min_path_sum.swift"
[class]{}-[func]{minPathSumDFSMem}
```
=== "Zig"
```zig title="min_path_sum.zig"
[class]{}-[func]{minPathSumDFSMem}
```
=== "Dart"
```dart title="min_path_sum.dart"
@@ -254,6 +242,18 @@ $$
[class]{}-[func]{min_path_sum_dfs_mem}
```
=== "C"
```c title="min_path_sum.c"
[class]{}-[func]{minPathSumDFSMem}
```
=== "Zig"
```zig title="min_path_sum.zig"
[class]{}-[func]{minPathSumDFSMem}
```
如下图所示,在引入记忆化后,所有子问题的解只需计算一次,因此时间复杂度取决于状态总数,即网格尺寸 $O(nm)$ 。
![记忆化搜索递归树](dp_solution_pipeline.assets/min_path_sum_dfs_mem.png)
@@ -262,10 +262,10 @@ $$
基于迭代实现动态规划解法。
=== "Java"
=== "Python"
```java title="min_path_sum.java"
[class]{min_path_sum}-[func]{minPathSumDP}
```python title="min_path_sum.py"
[class]{}-[func]{min_path_sum_dp}
```
=== "C++"
@@ -274,10 +274,16 @@ $$
[class]{}-[func]{minPathSumDP}
```
=== "Python"
=== "Java"
```python title="min_path_sum.py"
[class]{}-[func]{min_path_sum_dp}
```java title="min_path_sum.java"
[class]{min_path_sum}-[func]{minPathSumDP}
```
=== "C#"
```csharp title="min_path_sum.cs"
[class]{min_path_sum}-[func]{minPathSumDP}
```
=== "Go"
@@ -286,6 +292,12 @@ $$
[class]{}-[func]{minPathSumDP}
```
=== "Swift"
```swift title="min_path_sum.swift"
[class]{}-[func]{minPathSumDP}
```
=== "JS"
```javascript title="min_path_sum.js"
@@ -298,30 +310,6 @@ $$
[class]{}-[func]{minPathSumDP}
```
=== "C"
```c title="min_path_sum.c"
[class]{}-[func]{minPathSumDP}
```
=== "C#"
```csharp title="min_path_sum.cs"
[class]{min_path_sum}-[func]{minPathSumDP}
```
=== "Swift"
```swift title="min_path_sum.swift"
[class]{}-[func]{minPathSumDP}
```
=== "Zig"
```zig title="min_path_sum.zig"
[class]{}-[func]{minPathSumDP}
```
=== "Dart"
```dart title="min_path_sum.dart"
@@ -334,6 +322,18 @@ $$
[class]{}-[func]{min_path_sum_dp}
```
=== "C"
```c title="min_path_sum.c"
[class]{}-[func]{minPathSumDP}
```
=== "Zig"
```zig title="min_path_sum.zig"
[class]{}-[func]{minPathSumDP}
```
下图展示了最小路径和的状态转移过程,其遍历了整个网格,**因此时间复杂度为 $O(nm)$** 。
数组 `dp` 大小为 $n \times m$ **因此空间复杂度为 $O(nm)$** 。
@@ -380,10 +380,10 @@ $$
请注意,因为数组 `dp` 只能表示一行的状态,所以我们无法提前初始化首列状态,而是在遍历每行中更新它。
=== "Java"
=== "Python"
```java title="min_path_sum.java"
[class]{min_path_sum}-[func]{minPathSumDPComp}
```python title="min_path_sum.py"
[class]{}-[func]{min_path_sum_dp_comp}
```
=== "C++"
@@ -392,10 +392,16 @@ $$
[class]{}-[func]{minPathSumDPComp}
```
=== "Python"
=== "Java"
```python title="min_path_sum.py"
[class]{}-[func]{min_path_sum_dp_comp}
```java title="min_path_sum.java"
[class]{min_path_sum}-[func]{minPathSumDPComp}
```
=== "C#"
```csharp title="min_path_sum.cs"
[class]{min_path_sum}-[func]{minPathSumDPComp}
```
=== "Go"
@@ -404,6 +410,12 @@ $$
[class]{}-[func]{minPathSumDPComp}
```
=== "Swift"
```swift title="min_path_sum.swift"
[class]{}-[func]{minPathSumDPComp}
```
=== "JS"
```javascript title="min_path_sum.js"
@@ -416,30 +428,6 @@ $$
[class]{}-[func]{minPathSumDPComp}
```
=== "C"
```c title="min_path_sum.c"
[class]{}-[func]{minPathSumDPComp}
```
=== "C#"
```csharp title="min_path_sum.cs"
[class]{min_path_sum}-[func]{minPathSumDPComp}
```
=== "Swift"
```swift title="min_path_sum.swift"
[class]{}-[func]{minPathSumDPComp}
```
=== "Zig"
```zig title="min_path_sum.zig"
[class]{}-[func]{minPathSumDPComp}
```
=== "Dart"
```dart title="min_path_sum.dart"
@@ -451,3 +439,15 @@ $$
```rust title="min_path_sum.rs"
[class]{}-[func]{min_path_sum_dp_comp}
```
=== "C"
```c title="min_path_sum.c"
[class]{}-[func]{minPathSumDPComp}
```
=== "Zig"
```zig title="min_path_sum.zig"
[class]{}-[func]{minPathSumDPComp}
```

View File

@@ -67,10 +67,10 @@ $$
### 代码实现
=== "Java"
=== "Python"
```java title="edit_distance.java"
[class]{edit_distance}-[func]{editDistanceDP}
```python title="edit_distance.py"
[class]{}-[func]{edit_distance_dp}
```
=== "C++"
@@ -79,10 +79,16 @@ $$
[class]{}-[func]{editDistanceDP}
```
=== "Python"
=== "Java"
```python title="edit_distance.py"
[class]{}-[func]{edit_distance_dp}
```java title="edit_distance.java"
[class]{edit_distance}-[func]{editDistanceDP}
```
=== "C#"
```csharp title="edit_distance.cs"
[class]{edit_distance}-[func]{editDistanceDP}
```
=== "Go"
@@ -91,6 +97,12 @@ $$
[class]{}-[func]{editDistanceDP}
```
=== "Swift"
```swift title="edit_distance.swift"
[class]{}-[func]{editDistanceDP}
```
=== "JS"
```javascript title="edit_distance.js"
@@ -103,30 +115,6 @@ $$
[class]{}-[func]{editDistanceDP}
```
=== "C"
```c title="edit_distance.c"
[class]{}-[func]{editDistanceDP}
```
=== "C#"
```csharp title="edit_distance.cs"
[class]{edit_distance}-[func]{editDistanceDP}
```
=== "Swift"
```swift title="edit_distance.swift"
[class]{}-[func]{editDistanceDP}
```
=== "Zig"
```zig title="edit_distance.zig"
[class]{}-[func]{editDistanceDP}
```
=== "Dart"
```dart title="edit_distance.dart"
@@ -139,6 +127,18 @@ $$
[class]{}-[func]{edit_distance_dp}
```
=== "C"
```c title="edit_distance.c"
[class]{}-[func]{editDistanceDP}
```
=== "Zig"
```zig title="edit_distance.zig"
[class]{}-[func]{editDistanceDP}
```
如下图所示,编辑距离问题的状态转移过程与背包问题非常类似,都可以看作是填写一个二维网格的过程。
=== "<1>"
@@ -192,10 +192,10 @@ $$
为此,我们可以使用一个变量 `leftup` 来暂存左上方的解 $dp[i-1, j-1]$ ,从而只需考虑左方和上方的解。此时的情况与完全背包问题相同,可使用正序遍历。
=== "Java"
=== "Python"
```java title="edit_distance.java"
[class]{edit_distance}-[func]{editDistanceDPComp}
```python title="edit_distance.py"
[class]{}-[func]{edit_distance_dp_comp}
```
=== "C++"
@@ -204,10 +204,16 @@ $$
[class]{}-[func]{editDistanceDPComp}
```
=== "Python"
=== "Java"
```python title="edit_distance.py"
[class]{}-[func]{edit_distance_dp_comp}
```java title="edit_distance.java"
[class]{edit_distance}-[func]{editDistanceDPComp}
```
=== "C#"
```csharp title="edit_distance.cs"
[class]{edit_distance}-[func]{editDistanceDPComp}
```
=== "Go"
@@ -216,6 +222,12 @@ $$
[class]{}-[func]{editDistanceDPComp}
```
=== "Swift"
```swift title="edit_distance.swift"
[class]{}-[func]{editDistanceDPComp}
```
=== "JS"
```javascript title="edit_distance.js"
@@ -228,30 +240,6 @@ $$
[class]{}-[func]{editDistanceDPComp}
```
=== "C"
```c title="edit_distance.c"
[class]{}-[func]{editDistanceDPComp}
```
=== "C#"
```csharp title="edit_distance.cs"
[class]{edit_distance}-[func]{editDistanceDPComp}
```
=== "Swift"
```swift title="edit_distance.swift"
[class]{}-[func]{editDistanceDPComp}
```
=== "Zig"
```zig title="edit_distance.zig"
[class]{}-[func]{editDistanceDPComp}
```
=== "Dart"
```dart title="edit_distance.dart"
@@ -263,3 +251,15 @@ $$
```rust title="edit_distance.rs"
[class]{}-[func]{edit_distance_dp_comp}
```
=== "C"
```c title="edit_distance.c"
[class]{}-[func]{editDistanceDPComp}
```
=== "Zig"
```zig title="edit_distance.zig"
[class]{}-[func]{editDistanceDPComp}
```

View File

@@ -14,12 +14,12 @@
本题的目标是求解方案数量,**我们可以考虑通过回溯来穷举所有可能性**。具体来说,将爬楼梯想象为一个多轮选择的过程:从地面出发,每轮选择上 $1$ 阶或 $2$ 阶,每当到达楼梯顶部时就将方案数量加 $1$ ,当越过楼梯顶部时就将其剪枝。
=== "Java"
=== "Python"
```java title="climbing_stairs_backtrack.java"
[class]{climbing_stairs_backtrack}-[func]{backtrack}
```python title="climbing_stairs_backtrack.py"
[class]{}-[func]{backtrack}
[class]{climbing_stairs_backtrack}-[func]{climbingStairsBacktrack}
[class]{}-[func]{climbing_stairs_backtrack}
```
=== "C++"
@@ -30,12 +30,20 @@
[class]{}-[func]{climbingStairsBacktrack}
```
=== "Python"
=== "Java"
```python title="climbing_stairs_backtrack.py"
[class]{}-[func]{backtrack}
```java title="climbing_stairs_backtrack.java"
[class]{climbing_stairs_backtrack}-[func]{backtrack}
[class]{}-[func]{climbing_stairs_backtrack}
[class]{climbing_stairs_backtrack}-[func]{climbingStairsBacktrack}
```
=== "C#"
```csharp title="climbing_stairs_backtrack.cs"
[class]{climbing_stairs_backtrack}-[func]{backtrack}
[class]{climbing_stairs_backtrack}-[func]{climbingStairsBacktrack}
```
=== "Go"
@@ -46,6 +54,14 @@
[class]{}-[func]{climbingStairsBacktrack}
```
=== "Swift"
```swift title="climbing_stairs_backtrack.swift"
[class]{}-[func]{backtrack}
[class]{}-[func]{climbingStairsBacktrack}
```
=== "JS"
```javascript title="climbing_stairs_backtrack.js"
@@ -62,38 +78,6 @@
[class]{}-[func]{climbingStairsBacktrack}
```
=== "C"
```c title="climbing_stairs_backtrack.c"
[class]{}-[func]{backtrack}
[class]{}-[func]{climbingStairsBacktrack}
```
=== "C#"
```csharp title="climbing_stairs_backtrack.cs"
[class]{climbing_stairs_backtrack}-[func]{backtrack}
[class]{climbing_stairs_backtrack}-[func]{climbingStairsBacktrack}
```
=== "Swift"
```swift title="climbing_stairs_backtrack.swift"
[class]{}-[func]{backtrack}
[class]{}-[func]{climbingStairsBacktrack}
```
=== "Zig"
```zig title="climbing_stairs_backtrack.zig"
[class]{}-[func]{backtrack}
[class]{}-[func]{climbingStairsBacktrack}
```
=== "Dart"
```dart title="climbing_stairs_backtrack.dart"
@@ -110,6 +94,22 @@
[class]{}-[func]{climbing_stairs_backtrack}
```
=== "C"
```c title="climbing_stairs_backtrack.c"
[class]{}-[func]{backtrack}
[class]{}-[func]{climbingStairsBacktrack}
```
=== "Zig"
```zig title="climbing_stairs_backtrack.zig"
[class]{}-[func]{backtrack}
[class]{}-[func]{climbingStairsBacktrack}
```
## 方法一:暴力搜索
回溯算法通常并不显式地对问题进行拆解,而是将问题看作一系列决策步骤,通过试探和剪枝,搜索所有可能的解。
@@ -136,12 +136,12 @@ $$
观察以下代码,它和标准回溯代码都属于深度优先搜索,但更加简洁。
=== "Java"
=== "Python"
```java title="climbing_stairs_dfs.java"
[class]{climbing_stairs_dfs}-[func]{dfs}
```python title="climbing_stairs_dfs.py"
[class]{}-[func]{dfs}
[class]{climbing_stairs_dfs}-[func]{climbingStairsDFS}
[class]{}-[func]{climbing_stairs_dfs}
```
=== "C++"
@@ -152,12 +152,20 @@ $$
[class]{}-[func]{climbingStairsDFS}
```
=== "Python"
=== "Java"
```python title="climbing_stairs_dfs.py"
[class]{}-[func]{dfs}
```java title="climbing_stairs_dfs.java"
[class]{climbing_stairs_dfs}-[func]{dfs}
[class]{}-[func]{climbing_stairs_dfs}
[class]{climbing_stairs_dfs}-[func]{climbingStairsDFS}
```
=== "C#"
```csharp title="climbing_stairs_dfs.cs"
[class]{climbing_stairs_dfs}-[func]{dfs}
[class]{climbing_stairs_dfs}-[func]{climbingStairsDFS}
```
=== "Go"
@@ -168,6 +176,14 @@ $$
[class]{}-[func]{climbingStairsDFS}
```
=== "Swift"
```swift title="climbing_stairs_dfs.swift"
[class]{}-[func]{dfs}
[class]{}-[func]{climbingStairsDFS}
```
=== "JS"
```javascript title="climbing_stairs_dfs.js"
@@ -184,38 +200,6 @@ $$
[class]{}-[func]{climbingStairsDFS}
```
=== "C"
```c title="climbing_stairs_dfs.c"
[class]{}-[func]{dfs}
[class]{}-[func]{climbingStairsDFS}
```
=== "C#"
```csharp title="climbing_stairs_dfs.cs"
[class]{climbing_stairs_dfs}-[func]{dfs}
[class]{climbing_stairs_dfs}-[func]{climbingStairsDFS}
```
=== "Swift"
```swift title="climbing_stairs_dfs.swift"
[class]{}-[func]{dfs}
[class]{}-[func]{climbingStairsDFS}
```
=== "Zig"
```zig title="climbing_stairs_dfs.zig"
[class]{}-[func]{dfs}
[class]{}-[func]{climbingStairsDFS}
```
=== "Dart"
```dart title="climbing_stairs_dfs.dart"
@@ -232,6 +216,22 @@ $$
[class]{}-[func]{climbing_stairs_dfs}
```
=== "C"
```c title="climbing_stairs_dfs.c"
[class]{}-[func]{dfs}
[class]{}-[func]{climbingStairsDFS}
```
=== "Zig"
```zig title="climbing_stairs_dfs.zig"
[class]{}-[func]{dfs}
[class]{}-[func]{climbingStairsDFS}
```
下图展示了暴力搜索形成的递归树。对于问题 $dp[n]$ ,其递归树的深度为 $n$ ,时间复杂度为 $O(2^n)$ 。指数阶属于爆炸式增长,如果我们输入一个比较大的 $n$ ,则会陷入漫长的等待之中。
![爬楼梯对应递归树](intro_to_dynamic_programming.assets/climbing_stairs_dfs_tree.png)
@@ -247,12 +247,12 @@ $$
1. 当首次计算 $dp[i]$ 时,我们将其记录至 `mem[i]` ,以便之后使用。
2. 当再次需要计算 $dp[i]$ 时,我们便可直接从 `mem[i]` 中获取结果,从而避免重复计算该子问题。
=== "Java"
=== "Python"
```java title="climbing_stairs_dfs_mem.java"
[class]{climbing_stairs_dfs_mem}-[func]{dfs}
```python title="climbing_stairs_dfs_mem.py"
[class]{}-[func]{dfs}
[class]{climbing_stairs_dfs_mem}-[func]{climbingStairsDFSMem}
[class]{}-[func]{climbing_stairs_dfs_mem}
```
=== "C++"
@@ -263,12 +263,20 @@ $$
[class]{}-[func]{climbingStairsDFSMem}
```
=== "Python"
=== "Java"
```python title="climbing_stairs_dfs_mem.py"
[class]{}-[func]{dfs}
```java title="climbing_stairs_dfs_mem.java"
[class]{climbing_stairs_dfs_mem}-[func]{dfs}
[class]{}-[func]{climbing_stairs_dfs_mem}
[class]{climbing_stairs_dfs_mem}-[func]{climbingStairsDFSMem}
```
=== "C#"
```csharp title="climbing_stairs_dfs_mem.cs"
[class]{climbing_stairs_dfs_mem}-[func]{dfs}
[class]{climbing_stairs_dfs_mem}-[func]{climbingStairsDFSMem}
```
=== "Go"
@@ -279,6 +287,14 @@ $$
[class]{}-[func]{climbingStairsDFSMem}
```
=== "Swift"
```swift title="climbing_stairs_dfs_mem.swift"
[class]{}-[func]{dfs}
[class]{}-[func]{climbingStairsDFSMem}
```
=== "JS"
```javascript title="climbing_stairs_dfs_mem.js"
@@ -295,38 +311,6 @@ $$
[class]{}-[func]{climbingStairsDFSMem}
```
=== "C"
```c title="climbing_stairs_dfs_mem.c"
[class]{}-[func]{dfs}
[class]{}-[func]{climbingStairsDFSMem}
```
=== "C#"
```csharp title="climbing_stairs_dfs_mem.cs"
[class]{climbing_stairs_dfs_mem}-[func]{dfs}
[class]{climbing_stairs_dfs_mem}-[func]{climbingStairsDFSMem}
```
=== "Swift"
```swift title="climbing_stairs_dfs_mem.swift"
[class]{}-[func]{dfs}
[class]{}-[func]{climbingStairsDFSMem}
```
=== "Zig"
```zig title="climbing_stairs_dfs_mem.zig"
[class]{}-[func]{dfs}
[class]{}-[func]{climbingStairsDFSMem}
```
=== "Dart"
```dart title="climbing_stairs_dfs_mem.dart"
@@ -343,6 +327,22 @@ $$
[class]{}-[func]{climbing_stairs_dfs_mem}
```
=== "C"
```c title="climbing_stairs_dfs_mem.c"
[class]{}-[func]{dfs}
[class]{}-[func]{climbingStairsDFSMem}
```
=== "Zig"
```zig title="climbing_stairs_dfs_mem.zig"
[class]{}-[func]{dfs}
[class]{}-[func]{climbingStairsDFSMem}
```
观察下图,**经过记忆化处理后,所有重叠子问题都只需被计算一次,时间复杂度被优化至 $O(n)$** ,这是一个巨大的飞跃。
![记忆化搜索对应递归树](intro_to_dynamic_programming.assets/climbing_stairs_dfs_memo_tree.png)
@@ -355,10 +355,10 @@ $$
由于动态规划不包含回溯过程,因此只需使用循环迭代实现,无须使用递归。在以下代码中,我们初始化一个数组 `dp` 来存储子问题的解,它起到了记忆化搜索中数组 `mem` 相同的记录作用。
=== "Java"
=== "Python"
```java title="climbing_stairs_dp.java"
[class]{climbing_stairs_dp}-[func]{climbingStairsDP}
```python title="climbing_stairs_dp.py"
[class]{}-[func]{climbing_stairs_dp}
```
=== "C++"
@@ -367,10 +367,16 @@ $$
[class]{}-[func]{climbingStairsDP}
```
=== "Python"
=== "Java"
```python title="climbing_stairs_dp.py"
[class]{}-[func]{climbing_stairs_dp}
```java title="climbing_stairs_dp.java"
[class]{climbing_stairs_dp}-[func]{climbingStairsDP}
```
=== "C#"
```csharp title="climbing_stairs_dp.cs"
[class]{climbing_stairs_dp}-[func]{climbingStairsDP}
```
=== "Go"
@@ -379,6 +385,12 @@ $$
[class]{}-[func]{climbingStairsDP}
```
=== "Swift"
```swift title="climbing_stairs_dp.swift"
[class]{}-[func]{climbingStairsDP}
```
=== "JS"
```javascript title="climbing_stairs_dp.js"
@@ -391,30 +403,6 @@ $$
[class]{}-[func]{climbingStairsDP}
```
=== "C"
```c title="climbing_stairs_dp.c"
[class]{}-[func]{climbingStairsDP}
```
=== "C#"
```csharp title="climbing_stairs_dp.cs"
[class]{climbing_stairs_dp}-[func]{climbingStairsDP}
```
=== "Swift"
```swift title="climbing_stairs_dp.swift"
[class]{}-[func]{climbingStairsDP}
```
=== "Zig"
```zig title="climbing_stairs_dp.zig"
[class]{}-[func]{climbingStairsDP}
```
=== "Dart"
```dart title="climbing_stairs_dp.dart"
@@ -427,6 +415,18 @@ $$
[class]{}-[func]{climbing_stairs_dp}
```
=== "C"
```c title="climbing_stairs_dp.c"
[class]{}-[func]{climbingStairsDP}
```
=== "Zig"
```zig title="climbing_stairs_dp.zig"
[class]{}-[func]{climbingStairsDP}
```
下图模拟了以上代码的执行过程。
![爬楼梯的动态规划过程](intro_to_dynamic_programming.assets/climbing_stairs_dp.png)
@@ -443,10 +443,10 @@ $$
细心的你可能发现,**由于 $dp[i]$ 只与 $dp[i-1]$ 和 $dp[i-2]$ 有关,因此我们无须使用一个数组 `dp` 来存储所有子问题的解**,而只需两个变量滚动前进即可。
=== "Java"
=== "Python"
```java title="climbing_stairs_dp.java"
[class]{climbing_stairs_dp}-[func]{climbingStairsDPComp}
```python title="climbing_stairs_dp.py"
[class]{}-[func]{climbing_stairs_dp_comp}
```
=== "C++"
@@ -455,10 +455,16 @@ $$
[class]{}-[func]{climbingStairsDPComp}
```
=== "Python"
=== "Java"
```python title="climbing_stairs_dp.py"
[class]{}-[func]{climbing_stairs_dp_comp}
```java title="climbing_stairs_dp.java"
[class]{climbing_stairs_dp}-[func]{climbingStairsDPComp}
```
=== "C#"
```csharp title="climbing_stairs_dp.cs"
[class]{climbing_stairs_dp}-[func]{climbingStairsDPComp}
```
=== "Go"
@@ -467,6 +473,12 @@ $$
[class]{}-[func]{climbingStairsDPComp}
```
=== "Swift"
```swift title="climbing_stairs_dp.swift"
[class]{}-[func]{climbingStairsDPComp}
```
=== "JS"
```javascript title="climbing_stairs_dp.js"
@@ -479,30 +491,6 @@ $$
[class]{}-[func]{climbingStairsDPComp}
```
=== "C"
```c title="climbing_stairs_dp.c"
[class]{}-[func]{climbingStairsDPComp}
```
=== "C#"
```csharp title="climbing_stairs_dp.cs"
[class]{climbing_stairs_dp}-[func]{climbingStairsDPComp}
```
=== "Swift"
```swift title="climbing_stairs_dp.swift"
[class]{}-[func]{climbingStairsDPComp}
```
=== "Zig"
```zig title="climbing_stairs_dp.zig"
[class]{}-[func]{climbingStairsDPComp}
```
=== "Dart"
```dart title="climbing_stairs_dp.dart"
@@ -515,6 +503,18 @@ $$
[class]{}-[func]{climbing_stairs_dp_comp}
```
=== "C"
```c title="climbing_stairs_dp.c"
[class]{}-[func]{climbingStairsDPComp}
```
=== "Zig"
```zig title="climbing_stairs_dp.zig"
[class]{}-[func]{climbingStairsDPComp}
```
观察以上代码,由于省去了数组 `dp` 占用的空间,因此空间复杂度从 $O(n)$ 降低至 $O(1)$ 。
在动态规划问题中,当前状态往往仅与前面有限个状态有关,这时我们可以只保留必要的状态,通过“降维”来节省内存空间。**这种空间优化技巧被称为“滚动变量”或“滚动数组”**。

View File

@@ -56,10 +56,10 @@ $$
- **终止条件**:当物品编号越界 $i = 0$ 或背包剩余容量为 $0$ 时,终止递归并返回价值 $0$ 。
- **剪枝**:若当前物品重量超出背包剩余容量,则只能不放入背包。
=== "Java"
=== "Python"
```java title="knapsack.java"
[class]{knapsack}-[func]{knapsackDFS}
```python title="knapsack.py"
[class]{}-[func]{knapsack_dfs}
```
=== "C++"
@@ -68,10 +68,16 @@ $$
[class]{}-[func]{knapsackDFS}
```
=== "Python"
=== "Java"
```python title="knapsack.py"
[class]{}-[func]{knapsack_dfs}
```java title="knapsack.java"
[class]{knapsack}-[func]{knapsackDFS}
```
=== "C#"
```csharp title="knapsack.cs"
[class]{knapsack}-[func]{knapsackDFS}
```
=== "Go"
@@ -80,6 +86,12 @@ $$
[class]{}-[func]{knapsackDFS}
```
=== "Swift"
```swift title="knapsack.swift"
[class]{}-[func]{knapsackDFS}
```
=== "JS"
```javascript title="knapsack.js"
@@ -92,30 +104,6 @@ $$
[class]{}-[func]{knapsackDFS}
```
=== "C"
```c title="knapsack.c"
[class]{}-[func]{knapsackDFS}
```
=== "C#"
```csharp title="knapsack.cs"
[class]{knapsack}-[func]{knapsackDFS}
```
=== "Swift"
```swift title="knapsack.swift"
[class]{}-[func]{knapsackDFS}
```
=== "Zig"
```zig title="knapsack.zig"
[class]{}-[func]{knapsackDFS}
```
=== "Dart"
```dart title="knapsack.dart"
@@ -128,6 +116,18 @@ $$
[class]{}-[func]{knapsack_dfs}
```
=== "C"
```c title="knapsack.c"
[class]{}-[func]{knapsackDFS}
```
=== "Zig"
```zig title="knapsack.zig"
[class]{}-[func]{knapsackDFS}
```
如下图所示,由于每个物品都会产生不选和选两条搜索分支,因此时间复杂度为 $O(2^n)$ 。
观察递归树,容易发现其中存在重叠子问题,例如 $dp[1, 10]$ 等。而当物品较多、背包容量较大,尤其是相同重量的物品较多时,重叠子问题的数量将会大幅增多。
@@ -140,10 +140,10 @@ $$
引入记忆化之后,**时间复杂度取决于子问题数量**,也就是 $O(n \times cap)$ 。
=== "Java"
=== "Python"
```java title="knapsack.java"
[class]{knapsack}-[func]{knapsackDFSMem}
```python title="knapsack.py"
[class]{}-[func]{knapsack_dfs_mem}
```
=== "C++"
@@ -152,10 +152,16 @@ $$
[class]{}-[func]{knapsackDFSMem}
```
=== "Python"
=== "Java"
```python title="knapsack.py"
[class]{}-[func]{knapsack_dfs_mem}
```java title="knapsack.java"
[class]{knapsack}-[func]{knapsackDFSMem}
```
=== "C#"
```csharp title="knapsack.cs"
[class]{knapsack}-[func]{knapsackDFSMem}
```
=== "Go"
@@ -164,6 +170,12 @@ $$
[class]{}-[func]{knapsackDFSMem}
```
=== "Swift"
```swift title="knapsack.swift"
[class]{}-[func]{knapsackDFSMem}
```
=== "JS"
```javascript title="knapsack.js"
@@ -176,30 +188,6 @@ $$
[class]{}-[func]{knapsackDFSMem}
```
=== "C"
```c title="knapsack.c"
[class]{}-[func]{knapsackDFSMem}
```
=== "C#"
```csharp title="knapsack.cs"
[class]{knapsack}-[func]{knapsackDFSMem}
```
=== "Swift"
```swift title="knapsack.swift"
[class]{}-[func]{knapsackDFSMem}
```
=== "Zig"
```zig title="knapsack.zig"
[class]{}-[func]{knapsackDFSMem}
```
=== "Dart"
```dart title="knapsack.dart"
@@ -212,6 +200,18 @@ $$
[class]{}-[func]{knapsack_dfs_mem}
```
=== "C"
```c title="knapsack.c"
[class]{}-[func]{knapsackDFSMem}
```
=== "Zig"
```zig title="knapsack.zig"
[class]{}-[func]{knapsackDFSMem}
```
下图展示了在记忆化递归中被剪掉的搜索分支。
![0-1 背包的记忆化搜索递归树](knapsack_problem.assets/knapsack_dfs_mem.png)
@@ -220,10 +220,10 @@ $$
动态规划实质上就是在状态转移中填充 $dp$ 表的过程,代码如下所示。
=== "Java"
=== "Python"
```java title="knapsack.java"
[class]{knapsack}-[func]{knapsackDP}
```python title="knapsack.py"
[class]{}-[func]{knapsack_dp}
```
=== "C++"
@@ -232,10 +232,16 @@ $$
[class]{}-[func]{knapsackDP}
```
=== "Python"
=== "Java"
```python title="knapsack.py"
[class]{}-[func]{knapsack_dp}
```java title="knapsack.java"
[class]{knapsack}-[func]{knapsackDP}
```
=== "C#"
```csharp title="knapsack.cs"
[class]{knapsack}-[func]{knapsackDP}
```
=== "Go"
@@ -244,6 +250,12 @@ $$
[class]{}-[func]{knapsackDP}
```
=== "Swift"
```swift title="knapsack.swift"
[class]{}-[func]{knapsackDP}
```
=== "JS"
```javascript title="knapsack.js"
@@ -256,30 +268,6 @@ $$
[class]{}-[func]{knapsackDP}
```
=== "C"
```c title="knapsack.c"
[class]{}-[func]{knapsackDP}
```
=== "C#"
```csharp title="knapsack.cs"
[class]{knapsack}-[func]{knapsackDP}
```
=== "Swift"
```swift title="knapsack.swift"
[class]{}-[func]{knapsackDP}
```
=== "Zig"
```zig title="knapsack.zig"
[class]{}-[func]{knapsackDP}
```
=== "Dart"
```dart title="knapsack.dart"
@@ -292,6 +280,18 @@ $$
[class]{}-[func]{knapsack_dp}
```
=== "C"
```c title="knapsack.c"
[class]{}-[func]{knapsackDP}
```
=== "Zig"
```zig title="knapsack.zig"
[class]{}-[func]{knapsackDP}
```
如下图所示,时间复杂度和空间复杂度都由数组 `dp` 大小决定,即 $O(n \times cap)$ 。
=== "<1>"
@@ -367,10 +367,10 @@ $$
在代码实现中,我们仅需将数组 `dp` 的第一维 $i$ 直接删除,并且把内循环更改为倒序遍历即可。
=== "Java"
=== "Python"
```java title="knapsack.java"
[class]{knapsack}-[func]{knapsackDPComp}
```python title="knapsack.py"
[class]{}-[func]{knapsack_dp_comp}
```
=== "C++"
@@ -379,10 +379,16 @@ $$
[class]{}-[func]{knapsackDPComp}
```
=== "Python"
=== "Java"
```python title="knapsack.py"
[class]{}-[func]{knapsack_dp_comp}
```java title="knapsack.java"
[class]{knapsack}-[func]{knapsackDPComp}
```
=== "C#"
```csharp title="knapsack.cs"
[class]{knapsack}-[func]{knapsackDPComp}
```
=== "Go"
@@ -391,6 +397,12 @@ $$
[class]{}-[func]{knapsackDPComp}
```
=== "Swift"
```swift title="knapsack.swift"
[class]{}-[func]{knapsackDPComp}
```
=== "JS"
```javascript title="knapsack.js"
@@ -403,30 +415,6 @@ $$
[class]{}-[func]{knapsackDPComp}
```
=== "C"
```c title="knapsack.c"
[class]{}-[func]{knapsackDPComp}
```
=== "C#"
```csharp title="knapsack.cs"
[class]{knapsack}-[func]{knapsackDPComp}
```
=== "Swift"
```swift title="knapsack.swift"
[class]{}-[func]{knapsackDPComp}
```
=== "Zig"
```zig title="knapsack.zig"
[class]{}-[func]{knapsackDPComp}
```
=== "Dart"
```dart title="knapsack.dart"
@@ -438,3 +426,15 @@ $$
```rust title="knapsack.rs"
[class]{}-[func]{knapsack_dp_comp}
```
=== "C"
```c title="knapsack.c"
[class]{}-[func]{knapsackDPComp}
```
=== "Zig"
```zig title="knapsack.zig"
[class]{}-[func]{knapsackDPComp}
```

View File

@@ -32,10 +32,10 @@ $$
对比两道题目的代码,状态转移中有一处从 $i-1$ 变为 $i$ ,其余完全一致。
=== "Java"
=== "Python"
```java title="unbounded_knapsack.java"
[class]{unbounded_knapsack}-[func]{unboundedKnapsackDP}
```python title="unbounded_knapsack.py"
[class]{}-[func]{unbounded_knapsack_dp}
```
=== "C++"
@@ -44,10 +44,16 @@ $$
[class]{}-[func]{unboundedKnapsackDP}
```
=== "Python"
=== "Java"
```python title="unbounded_knapsack.py"
[class]{}-[func]{unbounded_knapsack_dp}
```java title="unbounded_knapsack.java"
[class]{unbounded_knapsack}-[func]{unboundedKnapsackDP}
```
=== "C#"
```csharp title="unbounded_knapsack.cs"
[class]{unbounded_knapsack}-[func]{unboundedKnapsackDP}
```
=== "Go"
@@ -56,6 +62,12 @@ $$
[class]{}-[func]{unboundedKnapsackDP}
```
=== "Swift"
```swift title="unbounded_knapsack.swift"
[class]{}-[func]{unboundedKnapsackDP}
```
=== "JS"
```javascript title="unbounded_knapsack.js"
@@ -68,30 +80,6 @@ $$
[class]{}-[func]{unboundedKnapsackDP}
```
=== "C"
```c title="unbounded_knapsack.c"
[class]{}-[func]{unboundedKnapsackDP}
```
=== "C#"
```csharp title="unbounded_knapsack.cs"
[class]{unbounded_knapsack}-[func]{unboundedKnapsackDP}
```
=== "Swift"
```swift title="unbounded_knapsack.swift"
[class]{}-[func]{unboundedKnapsackDP}
```
=== "Zig"
```zig title="unbounded_knapsack.zig"
[class]{}-[func]{unboundedKnapsackDP}
```
=== "Dart"
```dart title="unbounded_knapsack.dart"
@@ -104,6 +92,18 @@ $$
[class]{}-[func]{unbounded_knapsack_dp}
```
=== "C"
```c title="unbounded_knapsack.c"
[class]{}-[func]{unboundedKnapsackDP}
```
=== "Zig"
```zig title="unbounded_knapsack.zig"
[class]{}-[func]{unboundedKnapsackDP}
```
### 空间优化
由于当前状态是从左边和上边的状态转移而来,**因此空间优化后应该对 $dp$ 表中的每一行采取正序遍历**。
@@ -130,10 +130,10 @@ $$
代码实现比较简单,仅需将数组 `dp` 的第一维删除。
=== "Java"
=== "Python"
```java title="unbounded_knapsack.java"
[class]{unbounded_knapsack}-[func]{unboundedKnapsackDPComp}
```python title="unbounded_knapsack.py"
[class]{}-[func]{unbounded_knapsack_dp_comp}
```
=== "C++"
@@ -142,10 +142,16 @@ $$
[class]{}-[func]{unboundedKnapsackDPComp}
```
=== "Python"
=== "Java"
```python title="unbounded_knapsack.py"
[class]{}-[func]{unbounded_knapsack_dp_comp}
```java title="unbounded_knapsack.java"
[class]{unbounded_knapsack}-[func]{unboundedKnapsackDPComp}
```
=== "C#"
```csharp title="unbounded_knapsack.cs"
[class]{unbounded_knapsack}-[func]{unboundedKnapsackDPComp}
```
=== "Go"
@@ -154,6 +160,12 @@ $$
[class]{}-[func]{unboundedKnapsackDPComp}
```
=== "Swift"
```swift title="unbounded_knapsack.swift"
[class]{}-[func]{unboundedKnapsackDPComp}
```
=== "JS"
```javascript title="unbounded_knapsack.js"
@@ -166,30 +178,6 @@ $$
[class]{}-[func]{unboundedKnapsackDPComp}
```
=== "C"
```c title="unbounded_knapsack.c"
[class]{}-[func]{unboundedKnapsackDPComp}
```
=== "C#"
```csharp title="unbounded_knapsack.cs"
[class]{unbounded_knapsack}-[func]{unboundedKnapsackDPComp}
```
=== "Swift"
```swift title="unbounded_knapsack.swift"
[class]{}-[func]{unboundedKnapsackDPComp}
```
=== "Zig"
```zig title="unbounded_knapsack.zig"
[class]{}-[func]{unboundedKnapsackDPComp}
```
=== "Dart"
```dart title="unbounded_knapsack.dart"
@@ -202,6 +190,18 @@ $$
[class]{}-[func]{unbounded_knapsack_dp_comp}
```
=== "C"
```c title="unbounded_knapsack.c"
[class]{}-[func]{unboundedKnapsackDPComp}
```
=== "Zig"
```zig title="unbounded_knapsack.zig"
[class]{}-[func]{unboundedKnapsackDPComp}
```
## 零钱兑换问题
背包问题是一大类动态规划问题的代表,其拥有很多的变种,例如零钱兑换问题。
@@ -251,10 +251,10 @@ $$
最后返回前,判断 $dp[n, amt]$ 是否等于 $amt + 1$ ,若是则返回 $-1$ ,代表无法凑出目标金额。
=== "Java"
=== "Python"
```java title="coin_change.java"
[class]{coin_change}-[func]{coinChangeDP}
```python title="coin_change.py"
[class]{}-[func]{coin_change_dp}
```
=== "C++"
@@ -263,10 +263,16 @@ $$
[class]{}-[func]{coinChangeDP}
```
=== "Python"
=== "Java"
```python title="coin_change.py"
[class]{}-[func]{coin_change_dp}
```java title="coin_change.java"
[class]{coin_change}-[func]{coinChangeDP}
```
=== "C#"
```csharp title="coin_change.cs"
[class]{coin_change}-[func]{coinChangeDP}
```
=== "Go"
@@ -275,6 +281,12 @@ $$
[class]{}-[func]{coinChangeDP}
```
=== "Swift"
```swift title="coin_change.swift"
[class]{}-[func]{coinChangeDP}
```
=== "JS"
```javascript title="coin_change.js"
@@ -287,30 +299,6 @@ $$
[class]{}-[func]{coinChangeDP}
```
=== "C"
```c title="coin_change.c"
[class]{}-[func]{coinChangeDP}
```
=== "C#"
```csharp title="coin_change.cs"
[class]{coin_change}-[func]{coinChangeDP}
```
=== "Swift"
```swift title="coin_change.swift"
[class]{}-[func]{coinChangeDP}
```
=== "Zig"
```zig title="coin_change.zig"
[class]{}-[func]{coinChangeDP}
```
=== "Dart"
```dart title="coin_change.dart"
@@ -323,6 +311,18 @@ $$
[class]{}-[func]{coin_change_dp}
```
=== "C"
```c title="coin_change.c"
[class]{}-[func]{coinChangeDP}
```
=== "Zig"
```zig title="coin_change.zig"
[class]{}-[func]{coinChangeDP}
```
下图展示了零钱兑换的动态规划过程,和完全背包非常相似。
=== "<1>"
@@ -374,10 +374,10 @@ $$
零钱兑换的空间优化的处理方式和完全背包一致。
=== "Java"
=== "Python"
```java title="coin_change.java"
[class]{coin_change}-[func]{coinChangeDPComp}
```python title="coin_change.py"
[class]{}-[func]{coin_change_dp_comp}
```
=== "C++"
@@ -386,10 +386,16 @@ $$
[class]{}-[func]{coinChangeDPComp}
```
=== "Python"
=== "Java"
```python title="coin_change.py"
[class]{}-[func]{coin_change_dp_comp}
```java title="coin_change.java"
[class]{coin_change}-[func]{coinChangeDPComp}
```
=== "C#"
```csharp title="coin_change.cs"
[class]{coin_change}-[func]{coinChangeDPComp}
```
=== "Go"
@@ -398,6 +404,12 @@ $$
[class]{}-[func]{coinChangeDPComp}
```
=== "Swift"
```swift title="coin_change.swift"
[class]{}-[func]{coinChangeDPComp}
```
=== "JS"
```javascript title="coin_change.js"
@@ -410,30 +422,6 @@ $$
[class]{}-[func]{coinChangeDPComp}
```
=== "C"
```c title="coin_change.c"
[class]{}-[func]{coinChangeDPComp}
```
=== "C#"
```csharp title="coin_change.cs"
[class]{coin_change}-[func]{coinChangeDPComp}
```
=== "Swift"
```swift title="coin_change.swift"
[class]{}-[func]{coinChangeDPComp}
```
=== "Zig"
```zig title="coin_change.zig"
[class]{}-[func]{coinChangeDPComp}
```
=== "Dart"
```dart title="coin_change.dart"
@@ -446,6 +434,18 @@ $$
[class]{}-[func]{coin_change_dp_comp}
```
=== "C"
```c title="coin_change.c"
[class]{}-[func]{coinChangeDPComp}
```
=== "Zig"
```zig title="coin_change.zig"
[class]{}-[func]{coinChangeDPComp}
```
## 零钱兑换问题 II
!!! question
@@ -468,10 +468,10 @@ $$
### 代码实现
=== "Java"
=== "Python"
```java title="coin_change_ii.java"
[class]{coin_change_ii}-[func]{coinChangeIIDP}
```python title="coin_change_ii.py"
[class]{}-[func]{coin_change_ii_dp}
```
=== "C++"
@@ -480,10 +480,16 @@ $$
[class]{}-[func]{coinChangeIIDP}
```
=== "Python"
=== "Java"
```python title="coin_change_ii.py"
[class]{}-[func]{coin_change_ii_dp}
```java title="coin_change_ii.java"
[class]{coin_change_ii}-[func]{coinChangeIIDP}
```
=== "C#"
```csharp title="coin_change_ii.cs"
[class]{coin_change_ii}-[func]{coinChangeIIDP}
```
=== "Go"
@@ -492,6 +498,12 @@ $$
[class]{}-[func]{coinChangeIIDP}
```
=== "Swift"
```swift title="coin_change_ii.swift"
[class]{}-[func]{coinChangeIIDP}
```
=== "JS"
```javascript title="coin_change_ii.js"
@@ -504,30 +516,6 @@ $$
[class]{}-[func]{coinChangeIIDP}
```
=== "C"
```c title="coin_change_ii.c"
[class]{}-[func]{coinChangeIIDP}
```
=== "C#"
```csharp title="coin_change_ii.cs"
[class]{coin_change_ii}-[func]{coinChangeIIDP}
```
=== "Swift"
```swift title="coin_change_ii.swift"
[class]{}-[func]{coinChangeIIDP}
```
=== "Zig"
```zig title="coin_change_ii.zig"
[class]{}-[func]{coinChangeIIDP}
```
=== "Dart"
```dart title="coin_change_ii.dart"
@@ -540,14 +528,26 @@ $$
[class]{}-[func]{coin_change_ii_dp}
```
=== "C"
```c title="coin_change_ii.c"
[class]{}-[func]{coinChangeIIDP}
```
=== "Zig"
```zig title="coin_change_ii.zig"
[class]{}-[func]{coinChangeIIDP}
```
### 空间优化
空间优化处理方式相同,删除硬币维度即可。
=== "Java"
=== "Python"
```java title="coin_change_ii.java"
[class]{coin_change_ii}-[func]{coinChangeIIDPComp}
```python title="coin_change_ii.py"
[class]{}-[func]{coin_change_ii_dp_comp}
```
=== "C++"
@@ -556,10 +556,16 @@ $$
[class]{}-[func]{coinChangeIIDPComp}
```
=== "Python"
=== "Java"
```python title="coin_change_ii.py"
[class]{}-[func]{coin_change_ii_dp_comp}
```java title="coin_change_ii.java"
[class]{coin_change_ii}-[func]{coinChangeIIDPComp}
```
=== "C#"
```csharp title="coin_change_ii.cs"
[class]{coin_change_ii}-[func]{coinChangeIIDPComp}
```
=== "Go"
@@ -568,6 +574,12 @@ $$
[class]{}-[func]{coinChangeIIDPComp}
```
=== "Swift"
```swift title="coin_change_ii.swift"
[class]{}-[func]{coinChangeIIDPComp}
```
=== "JS"
```javascript title="coin_change_ii.js"
@@ -580,30 +592,6 @@ $$
[class]{}-[func]{coinChangeIIDPComp}
```
=== "C"
```c title="coin_change_ii.c"
[class]{}-[func]{coinChangeIIDPComp}
```
=== "C#"
```csharp title="coin_change_ii.cs"
[class]{coin_change_ii}-[func]{coinChangeIIDPComp}
```
=== "Swift"
```swift title="coin_change_ii.swift"
[class]{}-[func]{coinChangeIIDPComp}
```
=== "Zig"
```zig title="coin_change_ii.zig"
[class]{}-[func]{coinChangeIIDPComp}
```
=== "Dart"
```dart title="coin_change_ii.dart"
@@ -615,3 +603,15 @@ $$
```rust title="coin_change_ii.rs"
[class]{}-[func]{coin_change_ii_dp_comp}
```
=== "C"
```c title="coin_change_ii.c"
[class]{}-[func]{coinChangeIIDPComp}
```
=== "Zig"
```zig title="coin_change_ii.zig"
[class]{}-[func]{coinChangeIIDPComp}
```