Revisit the English version (#1835)

* Review the English version using Claude-4.5.

* Update mkdocs.yml

* Align the section titles.

* Bug fixes
This commit is contained in:
Yudong Jin
2025-12-30 17:54:01 +08:00
committed by GitHub
parent 091afd38b4
commit 45e1295241
106 changed files with 4195 additions and 3398 deletions

View File

@@ -6,23 +6,23 @@ In this section, we first solve another common knapsack problem: the unbounded k
!!! question
Given $n$ items, where the weight of the $i^{th}$ item is $wgt[i-1]$ and its value is $val[i-1]$, and a backpack with a capacity of $cap$. **Each item can be selected multiple times**. What is the maximum value of the items that can be put into the backpack without exceeding its capacity? See the example below.
Given $n$ items, where the weight of the $i$-th item is $wgt[i-1]$ and its value is $val[i-1]$, and a knapsack with capacity $cap$. **Each item can be selected multiple times**. What is the maximum value that can be placed in the knapsack within the capacity limit? An example is shown in the figure below.
![Example data for the unbounded knapsack problem](unbounded_knapsack_problem.assets/unbounded_knapsack_example.png)
![Example data for unbounded knapsack problem](unbounded_knapsack_problem.assets/unbounded_knapsack_example.png)
### Dynamic programming approach
The unbounded knapsack problem is very similar to the 0-1 knapsack problem, **the only difference being that there is no limit on the number of times an item can be chosen**.
The unbounded knapsack problem is very similar to the 0-1 knapsack problem, **differing only in that there is no limit on the number of times an item can be selected**.
- In the 0-1 knapsack problem, there is only one of each item, so after placing item $i$ into the backpack, you can only choose from the previous $i-1$ items.
- In the unbounded knapsack problem, the quantity of each item is unlimited, so after placing item $i$ in the backpack, **you can still choose from the previous $i$ items**.
- In the 0-1 knapsack problem, there is only one of each type of item, so after placing item $i$ in the knapsack, we can only choose from the first $i-1$ items.
- In the unbounded knapsack problem, the quantity of each type of item is unlimited, so after placing item $i$ in the knapsack, **we can still choose from the first $i$ items**.
Under the rules of the unbounded knapsack problem, the state $[i, c]$ can change in two ways.
Under the rules of the unbounded knapsack problem, the changes in state $[i, c]$ are divided into two cases.
- **Not putting item $i$ in**: As with the 0-1 knapsack problem, transition to $[i-1, c]$.
- **Putting item $i$ in**: Unlike the 0-1 knapsack problem, transition to $[i, c-wgt[i-1]]$.
- **Not putting item $i$**: Same as the 0-1 knapsack problem, transfer to $[i-1, c]$.
- **Putting item $i$**: Different from the 0-1 knapsack problem, transfer to $[i, c-wgt[i-1]]$.
The state transition equation thus becomes:
Thus, the state transition equation becomes:
$$
dp[i, c] = \max(dp[i-1, c], dp[i, c - wgt[i-1]] + val[i-1])
@@ -30,7 +30,7 @@ $$
### Code implementation
Comparing the code for the two problems, the state transition changes from $i-1$ to $i$, the rest is completely identical:
Comparing the code for the two problems, there is one change in state transition from $i-1$ to $i$, with everything else identical:
```src
[file]{unbounded_knapsack}-[class]{}-[func]{unbounded_knapsack_dp}
@@ -38,12 +38,12 @@ Comparing the code for the two problems, the state transition changes from $i-1$
### Space optimization
Since the current state comes from the state to the left and above, **the space-optimized solution should perform a forward traversal for each row in the $dp$ table**.
Since the current state is transferred from states on the left and above, **after space optimization, each row in the $dp$ table should be traversed in forward order**.
This traversal order is the opposite of that for the 0-1 knapsack. Please refer to the figure below to understand the difference.
This traversal order is exactly opposite to the 0-1 knapsack. Please refer to the figure below to understand the difference between the two.
=== "<1>"
![Dynamic programming process for the unbounded knapsack problem after space optimization](unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step1.png)
![Space-optimized dynamic programming process for unbounded knapsack problem](unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step1.png)
=== "<2>"
![unbounded_knapsack_dp_comp_step2](unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step2.png)
@@ -60,7 +60,7 @@ This traversal order is the opposite of that for the 0-1 knapsack. Please refer
=== "<6>"
![unbounded_knapsack_dp_comp_step6](unbounded_knapsack_problem.assets/unbounded_knapsack_dp_comp_step6.png)
The code implementation is quite simple, just remove the first dimension of the array `dp`:
The code implementation is relatively simple, just delete the first dimension of the array `dp`:
```src
[file]{unbounded_knapsack}-[class]{}-[func]{unbounded_knapsack_dp_comp}
@@ -68,59 +68,59 @@ The code implementation is quite simple, just remove the first dimension of the
## Coin change problem
The knapsack problem is a representative of a large class of dynamic programming problems and has many variants, such as the coin change problem.
The knapsack problem represents a large class of dynamic programming problems and has many variants, such as the coin change problem.
!!! question
Given $n$ types of coins, the denomination of the $i^{th}$ type of coin is $coins[i - 1]$, and the target amount is $amt$. **Each type of coin can be selected multiple times**. What is the minimum number of coins needed to make up the target amount? If it is impossible to make up the target amount, return $-1$. See the example below.
Given $n$ types of coins, where the denomination of the $i$-th type of coin is $coins[i - 1]$, and the target amount is $amt$. **Each type of coin can be selected multiple times**. What is the minimum number of coins needed to make up the target amount? If it is impossible to make up the target amount, return $-1$. An example is shown in the figure below.
![Example data for the coin change problem](unbounded_knapsack_problem.assets/coin_change_example.png)
![Example data for coin change problem](unbounded_knapsack_problem.assets/coin_change_example.png)
### Dynamic programming approach
**The coin change can be seen as a special case of the unbounded knapsack problem**, sharing the following similarities and differences.
**The coin change problem can be viewed as a special case of the unbounded knapsack problem**, with the following connections and differences.
- The two problems can be converted into each other: "item" corresponds to "coin", "item weight" corresponds to "coin denomination", and "backpack capacity" corresponds to "target amount".
- The optimization goals are opposite: the unbounded knapsack problem aims to maximize the value of items, while the coin change problem aims to minimize the number of coins.
- The unbounded knapsack problem seeks solutions "not exceeding" the backpack capacity, while the coin change seeks solutions that "exactly" make up the target amount.
- The two problems can be converted to each other: "item" corresponds to "coin", "item weight" corresponds to "coin denomination", and "knapsack capacity" corresponds to "target amount".
- The optimization goals are opposite: the unbounded knapsack problem aims to maximize item value, while the coin change problem aims to minimize the number of coins.
- The unbounded knapsack problem seeks solutions "not exceeding" the knapsack capacity, while the coin change problem seeks solutions that "exactly" make up the target amount.
**First step: Think through each round's decision-making, define the state, and thus derive the $dp$ table**
**Step 1: Think about the decisions in each round, define the state, and thus obtain the $dp$ table**
The state $[i, a]$ corresponds to the sub-problem: **the minimum number of coins that can make up the amount $a$ using the first $i$ types of coins**, denoted as $dp[i, a]$.
State $[i, a]$ corresponds to the subproblem: **the minimum number of coins among the first $i$ types of coins that can make up amount $a$**, denoted as $dp[i, a]$.
The two-dimensional $dp$ table is of size $(n+1) \times (amt+1)$.
The two-dimensional $dp$ table has size $(n+1) \times (amt+1)$.
**Second step: Identify the optimal substructure and derive the state transition equation**
**Step 2: Identify the optimal substructure, and then derive the state transition equation**
This problem differs from the unbounded knapsack problem in two aspects of the state transition equation.
This problem differs from the unbounded knapsack problem in the following two aspects regarding the state transition equation.
- This problem seeks the minimum, so the operator $\max()$ needs to be changed to $\min()$.
- The optimization is focused on the number of coins, so simply add $+1$ when a coin is chosen.
- This problem seeks the minimum value, so the operator $\max()$ needs to be changed to $\min()$.
- The optimization target is the number of coins rather than item value, so when a coin is selected, simply execute $+1$.
$$
dp[i, a] = \min(dp[i-1, a], dp[i, a - coins[i-1]] + 1)
$$
**Third step: Define boundary conditions and state transition order**
**Step 3: Determine boundary conditions and state transition order**
When the target amount is $0$, the minimum number of coins needed to make it up is $0$, so all $dp[i, 0]$ in the first column are $0$.
When the target amount is $0$, the minimum number of coins needed to make it up is $0$, so all $dp[i, 0]$ in the first column equal $0$.
When there are no coins, **it is impossible to make up any amount >0**, which is an invalid solution. To allow the $\min()$ function in the state transition equation to recognize and filter out invalid solutions, consider using $+\infty$ to represent them, i.e., set all $dp[0, a]$ in the first row to $+\infty$.
When there are no coins, **it is impossible to make up any amount $> 0$**, which is an invalid solution. To enable the $\min()$ function in the state transition equation to identify and filter out invalid solutions, we consider using $+ \infty$ to represent them, i.e., set all $dp[0, a]$ in the first row to $+ \infty$.
### Code implementation
Most programming languages do not provide a $+\infty$ variable, only the maximum value of an integer `int` can be used as a substitute. This can lead to overflow: the $+1$ operation in the state transition equation may overflow.
Most programming languages do not provide a $+ \infty$ variable, and can only use the maximum value of integer type `int` as a substitute. However, this can lead to large number overflow: the $+ 1$ operation in the state transition equation may cause overflow.
For this reason, we use the number $amt + 1$ to represent an invalid solution, because the maximum number of coins needed to make up $amt$ is at most $amt$. Before returning the result, check if $dp[n, amt]$ equals $amt + 1$, and if so, return $-1$, indicating that the target amount cannot be made up. The code is as follows:
For this reason, we use the number $amt + 1$ to represent invalid solutions, because the maximum number of coins needed to make up $amt$ is at most $amt$. Before returning, check whether $dp[n, amt]$ equals $amt + 1$; if so, return $-1$, indicating that the target amount cannot be made up. The code is as follows:
```src
[file]{coin_change}-[class]{}-[func]{coin_change_dp}
```
The figure below show the dynamic programming process for the coin change problem, which is very similar to the unbounded knapsack problem.
The figure below shows the dynamic programming process for coin change, which is very similar to the unbounded knapsack problem.
=== "<1>"
![Dynamic programming process for the coin change problem](unbounded_knapsack_problem.assets/coin_change_dp_step1.png)
![Dynamic programming process for coin change problem](unbounded_knapsack_problem.assets/coin_change_dp_step1.png)
=== "<2>"
![coin_change_dp_step2](unbounded_knapsack_problem.assets/coin_change_dp_step2.png)
@@ -166,7 +166,7 @@ The figure below show the dynamic programming process for the coin change proble
### Space optimization
The space optimization for the coin change problem is handled in the same way as for the unbounded knapsack problem:
The space optimization for the coin change problem is handled in the same way as the unbounded knapsack problem:
```src
[file]{coin_change}-[class]{}-[func]{coin_change_dp_comp}
@@ -176,21 +176,21 @@ The space optimization for the coin change problem is handled in the same way as
!!! question
Given $n$ types of coins, where the denomination of the $i^{th}$ type of coin is $coins[i - 1]$, and the target amount is $amt$. Each type of coin can be selected multiple times, **ask how many combinations of coins can make up the target amount**. See the example below.
Given $n$ types of coins, where the denomination of the $i$-th type of coin is $coins[i - 1]$, and the target amount is $amt$. Each type of coin can be selected multiple times. **What is the number of coin combinations that can make up the target amount?** An example is shown in the figure below.
![Example data for Coin Change Problem II](unbounded_knapsack_problem.assets/coin_change_ii_example.png)
![Example data for coin change problem II](unbounded_knapsack_problem.assets/coin_change_ii_example.png)
### Dynamic programming approach
Compared to the previous problem, the goal of this problem is to determine the number of combinations, so the sub-problem becomes: **the number of combinations that can make up amount $a$ using the first $i$ types of coins**. The $dp$ table remains a two-dimensional matrix of size $(n+1) \times (amt + 1)$.
Compared to the previous problem, this problem's goal is to find the number of combinations, so the subproblem becomes: **the number of combinations among the first $i$ types of coins that can make up amount $a$**. The $dp$ table remains a two-dimensional matrix of size $(n+1) \times (amt + 1)$.
The number of combinations for the current state is the sum of the combinations from not selecting the current coin and selecting the current coin. The state transition equation is:
The number of combinations for the current state equals the sum of the combinations from not selecting the current coin and selecting the current coin. The state transition equation is:
$$
dp[i, a] = dp[i-1, a] + dp[i, a - coins[i-1]]
$$
When the target amount is $0$, no coins are needed to make up the target amount, so all $dp[i, 0]$ in the first column should be initialized to $1$. When there are no coins, it is impossible to make up any amount >0, so all $dp[0, a]$ in the first row should be set to $0$.
When the target amount is $0$, no coins need to be selected to make up the target amount, so all $dp[i, 0]$ in the first column should be initialized to $1$. When there are no coins, it is impossible to make up any amount $>0$, so all $dp[0, a]$ in the first row equal $0$.
### Code implementation
@@ -200,7 +200,7 @@ When the target amount is $0$, no coins are needed to make up the target amount,
### Space optimization
The space optimization approach is the same, just remove the coin dimension:
The space optimization is handled in the same way, just delete the coin dimension:
```src
[file]{coin_change_ii}-[class]{}-[func]{coin_change_ii_dp_comp}