@@ -17,67 +17,59 @@ using namespace std;
17
17
18
18
class Solution {
19
19
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 ;
32
39
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
+ }
36
64
}
37
65
}
38
66
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
41
69
return -1 ;
42
70
}
43
71
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];
82
74
}
83
75
};
0 commit comments