-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy path0518-Coin_Change_II.cpp
More file actions
131 lines (117 loc) · 3.32 KB
/
0518-Coin_Change_II.cpp
File metadata and controls
131 lines (117 loc) · 3.32 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*******************************************************************************
* 0518-Coin_Change_II.cpp
* Billy.Ljm
* 11 August 2023
*
* =======
* Problem
* =======
* https://leetcode.com/problems/coin-change-ii/
*
* You are given an integer array coins representing coins of different
* denominations and an integer amount representing a total amount of money.
*
* 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.
*
* You may assume that you have an infinite number of each kind of coin.
*
* The answer is guaranteed to fit into a signed 32-bit integer.
*
* ===========
* My Approach
* ===========
* We'll use memoised recursion, where we find the number of combinations to
* make up a smaller amount, then use that to find the same for a larget amount.
*
* However, this can lead to double counting since making an amount of 3 with
* coins of 1 and 2 will lead to [1]+2 and [1+1, 2]+1, where the 2+1 is double
* counted. Thus, to avoid this, we'll prevent the use of coins smaller than the
* previously used coin.
*
* This has a time complexity of O(n*m), and a space complexity of O(n*m), where
* n is the total amount divided by the minimum coin and m is the number of coins
******************************************************************************/
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
/**
* << operator for vectors
*/
template <typename T>
std::ostream& operator<<(std::ostream& os, const std::vector<T>& v) {
os << "[";
for (const auto elem : v) {
os << elem << ",";
}
if (v.size() > 0) os << "\b";
os << "]";
return os;
}
/**
* << operator for map
*/
template <typename KeyType, typename ValueType>
std::ostream& operator<<(std::ostream& os,
const std::unordered_map<KeyType, ValueType>& myMap) {
os << "[";
for (const auto& pair : myMap) {
os << pair.first << ":" << pair.second << ",";
}
if (myMap.size() > 0) os << "\b";
os << "]";
return os;
}
/**
* Solution
*/
class Solution {
vector<unordered_map<int, int>> memo; // memo[mincoin][amt] = num combinations
public:
int change(int amount, vector<int>& coins) {
memo = vector<unordered_map<int, int>>(coins.size());
return recurse(amount, coins, 0);
}
int recurse(int amount, vector<int>& coins, int mincoin) {
// base case
if (amount < 0) return 0;
else if (amount == 0) return 1;
// memoised
else if (memo[mincoin].find(amount) != memo[mincoin].end()) {
return memo[mincoin][amount];
}
// recurse
else {
memo[mincoin][amount] = 0;
for (int i = mincoin; i < coins.size(); i++) {
memo[mincoin][amount] += recurse(amount - coins[i], coins, i);
}
return memo[mincoin][amount];
}
}
};
/**
* Test cases
*/
int main(void) {
Solution sol;
int amount;
vector<int> coins;
// test case 1
amount = 5;
coins = { 1,2,5 };
std::cout << "change(" << amount << "," << coins << ") = ";
std::cout << sol.change(amount, coins) << std::endl;
// test case 2
amount = 3;
coins = { 2 };
std::cout << "change(" << amount << "," << coins << ") = ";
std::cout << sol.change(amount, coins) << std::endl;
// test case 3
amount = 10;
coins = { 10 };
std::cout << "change(" << amount << "," << coins << ") = ";
std::cout << sol.change(amount, coins) << std::endl;
return 0;
}