Skip to content

feat: add solutions to lc problem: No.518 #2498

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 5 additions & 7 deletions solution/0300-0399/0322.Coin Change/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,12 +76,6 @@ $$

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

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

相似题目:

- [279. 完全平方数](https://github.com/doocs/leetcode/blob/main/solution/0200-0299/0279.Perfect%20Squares/README.md)

<!-- tabs:start -->

```python
Expand Down Expand Up @@ -237,7 +231,11 @@ var coinChange = function (coins, amount) {

<!-- tabs:end -->

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

相似题目:

- [279. 完全平方数](https://github.com/doocs/leetcode/blob/main/solution/0200-0299/0279.Perfect%20Squares/README.md)

<!-- tabs:start -->

Expand Down
34 changes: 32 additions & 2 deletions solution/0300-0399/0322.Coin Change/README_EN.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,33 @@

## Solutions

### Solution 1
### Solution 1: Dynamic Programming (Complete Knapsack)

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.

We can enumerate the quantity $k$ of the last coin used, then we have:

$$
f[i][j] = \min(f[i - 1][j], f[i - 1][j - x] + 1, \cdots, f[i - 1][j - k \times x] + k)
$$

where $x$ represents the face value of the $i$-th type of coin.

Let $j = j - x$, then we have:

$$
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)
$$

Substituting the second equation into the first one, we can get the following state transition equation:

$$
f[i][j] = \min(f[i - 1][j], f[i][j - x] + 1)
$$

The final answer is $f[m][n]$.

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.

<!-- tabs:start -->

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

<!-- tabs:end -->

### Solution 2
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)$.

Similar problems:

- [279. Perfect Squares](https://github.com/doocs/leetcode/blob/main/solution/0200-0299/0279.Perfect%20Squares/README_EN.md)

<!-- tabs:start -->

Expand Down
195 changes: 136 additions & 59 deletions solution/0500-0599/0518.Coin Change II/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -61,35 +61,65 @@

## 解法

### 方法一
### 方法一:动态规划(完全背包)

我们定义 $f[i][j]$ 表示使用前 $i$ 种硬币,凑出金额 $j$ 的硬币组合数。初始时 $f[0][0] = 1$,其余位置的值均为 $0$。

我们可以枚举使用的最后一枚硬币的数量 $k$,那么有式子一:

$$
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]
$$

其中 $x$ 表示第 $i$ 种硬币的面值。

不妨令 $j = j - x$,那么有式子二:

$$
f[i][j - x] = f[i - 1][j - x] + f[i - 1][j - 2 \times x] + \cdots + f[i - 1][j - k \times x]
$$

将式子二代入式子一,得到:

$$
f[i][j] = f[i - 1][j] + f[i][j - x]
$$

最终的答案为 $f[m][n]$,其中 $m$ 和 $n$ 分别表示硬币的种类数和总金额。

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

<!-- tabs:start -->

```python
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
dp = [0] * (amount + 1)
dp[0] = 1
for coin in coins:
for j in range(coin, amount + 1):
dp[j] += dp[j - coin]
return dp[-1]
m, n = len(coins), amount
f = [[0] * (n + 1) for _ in range(m + 1)]
f[0][0] = 1
for i, x in enumerate(coins, 1):
for j in range(n + 1):
f[i][j] = f[i - 1][j]
if j >= x:
f[i][j] += f[i][j - x]
return f[m][n]
```

```java
class Solution {
public int change(int amount, int[] coins) {
int m = coins.length;
int[][] dp = new int[m + 1][amount + 1];
dp[0][0] = 1;
int m = coins.length, n = amount;
int[][] f = new int[m + 1][n + 1];
f[0][0] = 1;
for (int i = 1; i <= m; ++i) {
for (int j = 0; j <= amount; ++j) {
for (int k = 0; k * coins[i - 1] <= j; ++k) {
dp[i][j] += dp[i - 1][j - coins[i - 1] * k];
for (int j = 0; j <= n; ++j) {
f[i][j] = f[i - 1][j];
if (j >= coins[i - 1]) {
f[i][j] += f[i][j - coins[i - 1]];
}
}
}
return dp[m][amount];
return f[m][n];
}
}
```
Expand All @@ -98,89 +128,136 @@ class Solution {
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int> dp(amount + 1);
dp[0] = 1;
for (auto coin : coins) {
for (int j = coin; j <= amount; ++j) {
dp[j] += dp[j - coin];
int m = coins.size(), n = amount;
int f[m + 1][n + 1];
memset(f, 0, sizeof(f));
f[0][0] = 1;
for (int i = 1; i <= m; ++i) {
for (int j = 0; j <= n; ++j) {
f[i][j] = f[i - 1][j];
if (j >= coins[i - 1]) {
f[i][j] += f[i][j - coins[i - 1]];
}
}
}
return dp[amount];
return f[m][n];
}
};
```

```go
func change(amount int, coins []int) int {
dp := make([]int, amount+1)
dp[0] = 1
for _, coin := range coins {
for j := coin; j <= amount; j++ {
dp[j] += dp[j-coin]
m, n := len(coins), amount
f := make([][]int, m+1)
for i := range f {
f[i] = make([]int, n+1)
}
f[0][0] = 1
for i := 1; i <= m; i++ {
for j := 0; j <= n; j++ {
f[i][j] = f[i-1][j]
if j >= coins[i-1] {
f[i][j] += f[i][j-coins[i-1]]
}
}
}
return dp[amount]
return f[m][n]
}
```

```ts
function change(amount: number, coins: number[]): number {
let dp = new Array(amount + 1).fill(0);
dp[0] = 1;
for (let coin of coins) {
for (let i = coin; i <= amount; ++i) {
dp[i] += dp[i - coin];
const [m, n] = [coins.length, amount];
const f: number[][] = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
f[0][0] = 1;
for (let i = 1; i <= m; ++i) {
for (let j = 0; j <= n; ++j) {
f[i][j] = f[i - 1][j];
if (j >= coins[i - 1]) {
f[i][j] += f[i][j - coins[i - 1]];
}
}
}
return dp.pop();
return f[m][n];
}
```

<!-- tabs:end -->

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

<!-- tabs:start -->

```python
class Solution:
def change(self, amount: int, coins: List[int]) -> int:
n = amount
f = [1] + [0] * n
for x in coins:
for j in range(x, n + 1):
f[j] += f[j - x]
return f[n]
```

```java
class Solution {
public int change(int amount, int[] coins) {
int m = coins.length;
int[][] dp = new int[m + 1][amount + 1];
dp[0][0] = 1;
for (int i = 1; i <= m; ++i) {
int v = coins[i - 1];
for (int j = 0; j <= amount; ++j) {
dp[i][j] = dp[i - 1][j];
if (j >= v) {
dp[i][j] += dp[i][j - v];
}
int n = amount;
int[] f = new int[n + 1];
f[0] = 1;
for (int x : coins) {
for (int j = x; j <= n; ++j) {
f[j] += f[j - x];
}
}
return dp[m][amount];
return f[n];
}
}
```

<!-- tabs:end -->

### 方法三

<!-- tabs:start -->

```java
```cpp
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for (int coin : coins) {
// 顺序遍历,0-1背包问题是倒序遍历
for (int j = coin; j <= amount; j++) {
dp[j] += dp[j - coin];
public:
int change(int amount, vector<int>& coins) {
int n = amount;
int f[n + 1];
memset(f, 0, sizeof(f));
f[0] = 1;
for (int x : coins) {
for (int j = x; j <= n; ++j) {
f[j] += f[j - x];
}
}
return dp[amount];
return f[n];
}
};
```

```go
func change(amount int, coins []int) int {
n := amount
f := make([]int, n+1)
f[0] = 1
for _, x := range coins {
for j := x; j <= n; j++ {
f[j] += f[j-x]
}
}
return f[n]
}
```

```ts
function change(amount: number, coins: number[]): number {
const n = amount;
const f: number[] = Array(n + 1).fill(0);
f[0] = 1;
for (const x of coins) {
for (let j = x; j <= n; ++j) {
f[j] += f[j - x];
}
}
return f[n];
}
```

Expand Down
Loading