mirror of
https://github.com/krahets/hello-algo.git
synced 2026-04-15 19:01:17 +08:00
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:
@@ -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.
|
||||
|
||||

|
||||

|
||||
|
||||
### 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>"
|
||||

|
||||

|
||||
|
||||
=== "<2>"
|
||||

|
||||
@@ -60,7 +60,7 @@ This traversal order is the opposite of that for the 0-1 knapsack. Please refer
|
||||
=== "<6>"
|
||||

|
||||
|
||||
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.
|
||||
|
||||

|
||||

|
||||
|
||||
### 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>"
|
||||

|
||||

|
||||
|
||||
=== "<2>"
|
||||

|
||||
@@ -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.
|
||||
|
||||

|
||||

|
||||
|
||||
### 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}
|
||||
|
||||
Reference in New Issue
Block a user