Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 51ed782

Browse files
authored
feat: add solutions to lc problems: No.322,518 (doocs#2498)
1 parent df3fafc commit 51ed782

File tree

15 files changed

+412
-182
lines changed

15 files changed

+412
-182
lines changed

solution/0300-0399/0322.Coin Change/README.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -76,12 +76,6 @@ $$
7676

7777
时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别为硬币的种类数和总金额。
7878

79-
注意到 $f[i][j]$ 只与 $f[i - 1][j]$ 和 $f[i][j - x]$ 有关,因此我们可以将二维数组优化为一维数组,空间复杂度降为 $O(n)$。
80-
81-
相似题目:
82-
83-
- [279. 完全平方数](https://github.com/doocs/leetcode/blob/main/solution/0200-0299/0279.Perfect%20Squares/README.md)
84-
8579
<!-- tabs:start -->
8680

8781
```python
@@ -237,7 +231,11 @@ var coinChange = function (coins, amount) {
237231

238232
<!-- tabs:end -->
239233

240-
### 方法二
234+
我们注意到 $f[i][j]$ 只与 $f[i - 1][j]$ 和 $f[i][j - x]$ 有关,因此我们可以将二维数组优化为一维数组,空间复杂度降为 $O(n)$。
235+
236+
相似题目:
237+
238+
- [279. 完全平方数](https://github.com/doocs/leetcode/blob/main/solution/0200-0299/0279.Perfect%20Squares/README.md)
241239

242240
<!-- tabs:start -->
243241

solution/0300-0399/0322.Coin Change/README_EN.md

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,33 @@
4646

4747
## Solutions
4848

49-
### Solution 1
49+
### Solution 1: Dynamic Programming (Complete Knapsack)
50+
51+
We define $f[i][j]$ as the minimum number of coins needed to make up the amount $j$ using the first $i$ types of coins. Initially, $f[0][0] = 0$, and the values of other positions are all positive infinity.
52+
53+
We can enumerate the quantity $k$ of the last coin used, then we have:
54+
55+
$$
56+
f[i][j] = \min(f[i - 1][j], f[i - 1][j - x] + 1, \cdots, f[i - 1][j - k \times x] + k)
57+
$$
58+
59+
where $x$ represents the face value of the $i$-th type of coin.
60+
61+
Let $j = j - x$, then we have:
62+
63+
$$
64+
f[i][j - x] = \min(f[i - 1][j - x], f[i - 1][j - 2 \times x] + 1, \cdots, f[i - 1][j - k \times x] + k - 1)
65+
$$
66+
67+
Substituting the second equation into the first one, we can get the following state transition equation:
68+
69+
$$
70+
f[i][j] = \min(f[i - 1][j], f[i][j - x] + 1)
71+
$$
72+
73+
The final answer is $f[m][n]$.
74+
75+
The time complexity is $O(m \times n)$, and the space complexity is $O(m \times n)$. Where $m$ and $n$ are the number of types of coins and the total amount, respectively.
5076

5177
<!-- tabs:start -->
5278

@@ -203,7 +229,11 @@ var coinChange = function (coins, amount) {
203229

204230
<!-- tabs:end -->
205231

206-
### Solution 2
232+
We notice that $f[i][j]$ is only related to $f[i - 1][j]$ and $f[i][j - x]$. Therefore, we can optimize the two-dimensional array into a one-dimensional array, reducing the space complexity to $O(n)$.
233+
234+
Similar problems:
235+
236+
- [279. Perfect Squares](https://github.com/doocs/leetcode/blob/main/solution/0200-0299/0279.Perfect%20Squares/README_EN.md)
207237

208238
<!-- tabs:start -->
209239

solution/0500-0599/0518.Coin Change II/README.md

Lines changed: 136 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -61,35 +61,65 @@
6161

6262
## 解法
6363

64-
### 方法一
64+
### 方法一:动态规划(完全背包)
65+
66+
我们定义 $f[i][j]$ 表示使用前 $i$ 种硬币,凑出金额 $j$ 的硬币组合数。初始时 $f[0][0] = 1$,其余位置的值均为 $0$。
67+
68+
我们可以枚举使用的最后一枚硬币的数量 $k$,那么有式子一:
69+
70+
$$
71+
f[i][j] = f[i - 1][j] + f[i - 1][j - x] + f[i - 1][j - 2 \times x] + \cdots + f[i - 1][j - k \times x]
72+
$$
73+
74+
其中 $x$ 表示第 $i$ 种硬币的面值。
75+
76+
不妨令 $j = j - x$,那么有式子二:
77+
78+
$$
79+
f[i][j - x] = f[i - 1][j - x] + f[i - 1][j - 2 \times x] + \cdots + f[i - 1][j - k \times x]
80+
$$
81+
82+
将式子二代入式子一,得到:
83+
84+
$$
85+
f[i][j] = f[i - 1][j] + f[i][j - x]
86+
$$
87+
88+
最终的答案为 $f[m][n]$,其中 $m$ 和 $n$ 分别表示硬币的种类数和总金额。
89+
90+
时间复杂度 $O(m \times n)$,空间复杂度 $O(m \times n)$。其中 $m$ 和 $n$ 分别为硬币的种类数和总金额。
6591

6692
<!-- tabs:start -->
6793

6894
```python
6995
class Solution:
7096
def change(self, amount: int, coins: List[int]) -> int:
71-
dp = [0] * (amount + 1)
72-
dp[0] = 1
73-
for coin in coins:
74-
for j in range(coin, amount + 1):
75-
dp[j] += dp[j - coin]
76-
return dp[-1]
97+
m, n = len(coins), amount
98+
f = [[0] * (n + 1) for _ in range(m + 1)]
99+
f[0][0] = 1
100+
for i, x in enumerate(coins, 1):
101+
for j in range(n + 1):
102+
f[i][j] = f[i - 1][j]
103+
if j >= x:
104+
f[i][j] += f[i][j - x]
105+
return f[m][n]
77106
```
78107

79108
```java
80109
class Solution {
81110
public int change(int amount, int[] coins) {
82-
int m = coins.length;
83-
int[][] dp = new int[m + 1][amount + 1];
84-
dp[0][0] = 1;
111+
int m = coins.length, n = amount;
112+
int[][] f = new int[m + 1][n + 1];
113+
f[0][0] = 1;
85114
for (int i = 1; i <= m; ++i) {
86-
for (int j = 0; j <= amount; ++j) {
87-
for (int k = 0; k * coins[i - 1] <= j; ++k) {
88-
dp[i][j] += dp[i - 1][j - coins[i - 1] * k];
115+
for (int j = 0; j <= n; ++j) {
116+
f[i][j] = f[i - 1][j];
117+
if (j >= coins[i - 1]) {
118+
f[i][j] += f[i][j - coins[i - 1]];
89119
}
90120
}
91121
}
92-
return dp[m][amount];
122+
return f[m][n];
93123
}
94124
}
95125
```
@@ -98,89 +128,136 @@ class Solution {
98128
class Solution {
99129
public:
100130
int change(int amount, vector<int>& coins) {
101-
vector<int> dp(amount + 1);
102-
dp[0] = 1;
103-
for (auto coin : coins) {
104-
for (int j = coin; j <= amount; ++j) {
105-
dp[j] += dp[j - coin];
131+
int m = coins.size(), n = amount;
132+
int f[m + 1][n + 1];
133+
memset(f, 0, sizeof(f));
134+
f[0][0] = 1;
135+
for (int i = 1; i <= m; ++i) {
136+
for (int j = 0; j <= n; ++j) {
137+
f[i][j] = f[i - 1][j];
138+
if (j >= coins[i - 1]) {
139+
f[i][j] += f[i][j - coins[i - 1]];
140+
}
106141
}
107142
}
108-
return dp[amount];
143+
return f[m][n];
109144
}
110145
};
111146
```
112147
113148
```go
114149
func change(amount int, coins []int) int {
115-
dp := make([]int, amount+1)
116-
dp[0] = 1
117-
for _, coin := range coins {
118-
for j := coin; j <= amount; j++ {
119-
dp[j] += dp[j-coin]
150+
m, n := len(coins), amount
151+
f := make([][]int, m+1)
152+
for i := range f {
153+
f[i] = make([]int, n+1)
154+
}
155+
f[0][0] = 1
156+
for i := 1; i <= m; i++ {
157+
for j := 0; j <= n; j++ {
158+
f[i][j] = f[i-1][j]
159+
if j >= coins[i-1] {
160+
f[i][j] += f[i][j-coins[i-1]]
161+
}
120162
}
121163
}
122-
return dp[amount]
164+
return f[m][n]
123165
}
124166
```
125167

126168
```ts
127169
function change(amount: number, coins: number[]): number {
128-
let dp = new Array(amount + 1).fill(0);
129-
dp[0] = 1;
130-
for (let coin of coins) {
131-
for (let i = coin; i <= amount; ++i) {
132-
dp[i] += dp[i - coin];
170+
const [m, n] = [coins.length, amount];
171+
const f: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
172+
f[0][0] = 1;
173+
for (let i = 1; i <= m; ++i) {
174+
for (let j = 0; j <= n; ++j) {
175+
f[i][j] = f[i - 1][j];
176+
if (j >= coins[i - 1]) {
177+
f[i][j] += f[i][j - coins[i - 1]];
178+
}
133179
}
134180
}
135-
return dp.pop();
181+
return f[m][n];
136182
}
137183
```
138184

139185
<!-- tabs:end -->
140186

141-
### 方法二
187+
我们注意到 $f[i][j]$ 只与 $f[i - 1][j]$ 和 $f[i][j - x]$ 有关,因此我们可以将二维数组优化为一维数组,空间复杂度降为 $O(n)$。
142188

143189
<!-- tabs:start -->
144190

191+
```python
192+
class Solution:
193+
def change(self, amount: int, coins: List[int]) -> int:
194+
n = amount
195+
f = [1] + [0] * n
196+
for x in coins:
197+
for j in range(x, n + 1):
198+
f[j] += f[j - x]
199+
return f[n]
200+
```
201+
145202
```java
146203
class Solution {
147204
public int change(int amount, int[] coins) {
148-
int m = coins.length;
149-
int[][] dp = new int[m + 1][amount + 1];
150-
dp[0][0] = 1;
151-
for (int i = 1; i <= m; ++i) {
152-
int v = coins[i - 1];
153-
for (int j = 0; j <= amount; ++j) {
154-
dp[i][j] = dp[i - 1][j];
155-
if (j >= v) {
156-
dp[i][j] += dp[i][j - v];
157-
}
205+
int n = amount;
206+
int[] f = new int[n + 1];
207+
f[0] = 1;
208+
for (int x : coins) {
209+
for (int j = x; j <= n; ++j) {
210+
f[j] += f[j - x];
158211
}
159212
}
160-
return dp[m][amount];
213+
return f[n];
161214
}
162215
}
163216
```
164217

165-
<!-- tabs:end -->
166-
167-
### 方法三
168-
169-
<!-- tabs:start -->
170-
171-
```java
218+
```cpp
172219
class Solution {
173-
public int change(int amount, int[] coins) {
174-
int[] dp = new int[amount + 1];
175-
dp[0] = 1;
176-
for (int coin : coins) {
177-
// 顺序遍历,0-1背包问题是倒序遍历
178-
for (int j = coin; j <= amount; j++) {
179-
dp[j] += dp[j - coin];
220+
public:
221+
int change(int amount, vector<int>& coins) {
222+
int n = amount;
223+
int f[n + 1];
224+
memset(f, 0, sizeof(f));
225+
f[0] = 1;
226+
for (int x : coins) {
227+
for (int j = x; j <= n; ++j) {
228+
f[j] += f[j - x];
180229
}
181230
}
182-
return dp[amount];
231+
return f[n];
232+
}
233+
};
234+
```
235+
236+
```go
237+
func change(amount int, coins []int) int {
238+
n := amount
239+
f := make([]int, n+1)
240+
f[0] = 1
241+
for _, x := range coins {
242+
for j := x; j <= n; j++ {
243+
f[j] += f[j-x]
244+
}
245+
}
246+
return f[n]
247+
}
248+
```
249+
250+
```ts
251+
function change(amount: number, coins: number[]): number {
252+
const n = amount;
253+
const f: number[] = Array(n + 1).fill(0);
254+
f[0] = 1;
255+
for (const x of coins) {
256+
for (let j = x; j <= n; ++j) {
257+
f[j] += f[j - x];
258+
}
183259
}
260+
return f[n];
184261
}
185262
```
186263

0 commit comments

Comments
 (0)