Skip to content

Commit a42e257

Browse files
committed
lc q518 round 0
1 parent 9a01d6c commit a42e257

File tree

1 file changed

+103
-0
lines changed

1 file changed

+103
-0
lines changed
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
/*
2+
You are given an integer array coins representing coins of different denominations and an integer amount representing a total amount of money.
3+
4+
Return the number of combinations that make up that amount. If that amount of money cannot be made up by any combination of the coins, return 0.
5+
6+
You may assume that you have an infinite number of each kind of coin.
7+
8+
The answer is guaranteed to fit into a signed 32-bit integer.
9+
10+
11+
12+
Example 1:
13+
14+
Input: amount = 5, coins = [1,2,5]
15+
Output: 4
16+
Explanation: there are four ways to make up the amount:
17+
5=5
18+
5=2+2+1
19+
5=2+1+1+1
20+
5=1+1+1+1+1
21+
Example 2:
22+
23+
Input: amount = 3, coins = [2]
24+
Output: 0
25+
Explanation: the amount of 3 cannot be made up just with coins of 2.
26+
Example 3:
27+
28+
Input: amount = 10, coins = [10]
29+
Output: 1
30+
31+
32+
Constraints:
33+
34+
1 <= coins.length <= 300
35+
1 <= coins[i] <= 5000
36+
All the values of coins are unique.
37+
0 <= amount <= 5000
38+
*/
39+
40+
41+
42+
// My Solution (fixed by GPT):
43+
class Solution {
44+
public int change(int amount, int[] coins) {
45+
int[] dp = new int[amount + 1];
46+
dp[0] = 1; // 有 1 种方法凑出 0 元:什么也不选
47+
48+
for (int coin : coins) {
49+
for (int i = coin; i <= amount; i++) {
50+
dp[i] += dp[i - coin]; // 把当前硬币加入组合
51+
}
52+
}
53+
return dp[amount];
54+
}
55+
}
56+
/*
57+
Why must loop coins outside and loop amounts (dp) inside but not vice versa
58+
59+
本题的关键是「组合数」而不是「排列数」
60+
用一个具体例子来说明:
61+
62+
金额=5,硬币=[1,2,5]
63+
跟踪dp数组的填充过程:
64+
65+
金额i=1:
66+
遍历硬币1: dp[1] += dp[0] = 0 + 1 = 1 (使用一个1元硬币)
67+
遍历硬币2: dp[1] += dp[-1] (不合法,跳过)
68+
遍历硬币5: dp[1] += dp[-4] (不合法,跳过)
69+
结果: dp[1] = 1
70+
71+
金额i=2:
72+
遍历硬币1: dp[2] += dp[1] = 0 + 1 = 1 (使用一个1元硬币)
73+
遍历硬币2: dp[2] += dp[0] = 1 + 1 = 2 (使用一个2元硬币)
74+
遍历硬币5: dp[2] += dp[-3] (不合法,跳过)
75+
结果: dp[2] = 2
76+
77+
金额i=3开始错误:
78+
遍历硬币1: dp[3] += dp[2] = 0 + 2 = 2 (使用一个1元硬币 + 之前凑2元的方法)
79+
遍历硬币2: dp[3] += dp[1] = 2 + 1 = 3 (使用一个2元硬币 + 之前凑1元的方法)
80+
遍历硬币5: dp[3] += dp[-2] (不合法,跳过)
81+
结果: dp[3] = 3
82+
83+
分析dp[3]=3的组成:
84+
得到了3种方式,但实际上组合数应该是2种:{1,1,1}, {1,2}
85+
为什么多计算了1种?因为{1,2}和{2,1}被当作不同的排列计算了
86+
87+
问题的根本原因:
88+
当先考虑金额,后考虑硬币时,在每个金额i处,都在重新考虑所有硬币
89+
这意味着在不同顺序中可能多次使用同一种硬币
90+
例如在计算dp[3]时,既考虑了"先用硬币1再用硬币2"的情况,也考虑了"先用硬币2再用硬币1"的情况
91+
92+
而外循环为硬币时,是按照硬币种类的固定顺序来构建解决方案,这确保了相同的组合只被计算一次,不管其元素的顺序如何。
93+
这就是为什么外循环为金额时计算的是排列数(考虑顺序),而题目要求的组合数(不考虑顺序)必须用外循环为硬币的方式来解决。
94+
95+
而正确的解法(外层循环硬币)确保了每种硬币被考虑的顺序是固定的
96+
97+
这样,对于每个硬币面值,按顺序考虑它可以如何构成各种金额。由于外层循环固定了考虑硬币的顺序,所以避免了重复计算组合。
98+
简单来说:
99+
外层循环硬币:计算的是组合数(不考虑顺序)
100+
外层循环金额:计算的是排列数(考虑顺序)
101+
102+
题目要求组合数,所以必须把硬币循环放在外层。
103+
*/

0 commit comments

Comments
 (0)