Skip to content

Commit ab5ff32

Browse files
committed
Implement coin-change
name: coin-change url: https://leetcode.com/problems/coin-change difficulty: 2 time: 64 ms time-rank: 89.46 % time-complexity: O(N) space: 14.1 MB space-rank: 69.66 % space-complexity: O(N) Fixes #311 Signed-off-by: Christopher Friedt <[email protected]>
1 parent 423db99 commit ab5ff32

File tree

1 file changed

+47
-55
lines changed

1 file changed

+47
-55
lines changed

coin-change.cpp

+47-55
Original file line numberDiff line numberDiff line change
@@ -17,67 +17,59 @@ using namespace std;
1717

1818
class Solution {
1919
public:
20-
int FC(unordered_map<int, int> &dp, const vector<int> &coins, int n) {
21-
22-
auto it = dp.find(n);
23-
if (dp.end() != it) {
24-
return it->second;
25-
}
26-
27-
int mmin = INT_MAX;
28-
for (auto &c : coins) {
29-
if (c > n) {
30-
continue;
31-
}
20+
int coinChange(vector<int> &coins, int amount) {
21+
/*
22+
If we look at the lowest coin value we could possibly have, 1,
23+
then it's easy to turn this problem into a 1-D DP problem, where
24+
we have an array of possible amounts in the range [0,amount].
25+
26+
A base case is FC(0) - fewest coins to make $0 is obviously 0.
27+
28+
The recursion is:
29+
FC(n) = 0, if n <= 0
30+
= 1, if n in coins
31+
= 1 + min(FC(n - c)), for c in coins
32+
= inf, if no coins can sum up to amount n
33+
*/
34+
// we choose inf to be INT_MAX because below we add 1 to dp[.]. If the value
35+
// were INT_MAX, then it would roll over to INT_MIN.
36+
constexpr int inf = INT_MAX - 1;
37+
vector<int> dp(amount + 1, inf);
38+
dp[0] = 0;
3239

33-
int r = FC(dp, coins, n - c);
34-
if (r != -1) {
35-
mmin = min(mmin, r);
40+
/*
41+
say coins = [1, 2, 5], amount = 11
42+
n c FC(n-c) min FC(n) comment
43+
0 - - - 0 zero coins for amount zero
44+
1 - - - 1 1 coin for anything in coins
45+
2 - - - 1 "
46+
5 - - - 1 "
47+
6 1 1 2 2 5 + 1 => 2 coins
48+
6 2 inf 2 2 '
49+
6 5 1 2 2 '
50+
7 1 2 3 3 5 + 1 + 1 => 3 coins
51+
7 2 1 2 2 5 + 2 => 2 coins
52+
7 5 inf 2 2 '
53+
...
54+
*/
55+
56+
// O(N)
57+
for (int n = 1; n <= amount; ++n) {
58+
// O(1) - maximum number of different types of coins is 12
59+
for (auto& c: coins) {
60+
if (n - c >= 0) {
61+
// choose inf to avoid integer rollover here.
62+
dp[n] = min(dp[n], 1 + dp[n - c]);
63+
}
3664
}
3765
}
3866

39-
if (mmin == INT_MAX) {
40-
dp[n] = -1;
67+
if (dp[amount] == inf) {
68+
// we were unable to arrive at amount using any sum from any coins
4169
return -1;
4270
}
4371

44-
dp[n] = 1 + mmin;
45-
return 1 + mmin;
46-
}
47-
48-
int coinChange(vector<int> &coins, int amount) {
49-
/*
50-
Let's think about a greedy algorithm first
51-
52-
if we first sort the coins, then start at the higher end
53-
we take off the largest amount possible until amount is less than the
54-
highest-valued coin.
55-
56-
that would certainly minimize the number of coins we needed to
57-
give out in change.
58-
59-
Is there a possibility that we might not be able to provide exact change
60-
using the greedy algorithm? Maybe?
61-
62-
An alternative is to start at the other end - so a not greedy algorithm.
63-
64-
We could potentially create an unordered_map<int,int> where the key is
65-
the amount and the value is the fewest coins for amount n. We could start
66-
out with FC(0) = 0, and for each coin, say FC(coin[i]) = 1. Then with the
67-
recursion, we would be looking at FC(n) = min(FC(n), FC(n - coins[i])), for
68-
all i. Use recursion first, and then potentially look at optimizing with a
69-
stack. This would be kind of like a depth-first search.
70-
71-
Since amount is limited to 10000, it might be a viable option to go bottom
72-
up.
73-
*/
74-
75-
unordered_map<int, int> dp;
76-
dp[0] = 0;
77-
for (auto &c : coins) {
78-
dp[c] = 1;
79-
}
80-
81-
return FC(dp, coins, amount);
72+
// the fewest coins to get amount, or FC(n)
73+
return dp[amount];
8274
}
8375
};

0 commit comments

Comments
 (0)