Coin Change
Problem
You are given an integer array coins representing coins of different denominations (e.g. 1 dollar, 5 dollars, etc) and an integer amount representing a target amount of money.
Return the fewest number of coins that you need to make up the exact target amount. If it is impossible to make up the amount, return -1.
You may assume that you have an unlimited number of each coin.
Examples
Example 1:
Input: coins = [1,5,10], amount = 12
Output: 3
Explanation: 12 = 10 + 1 + 1. Note that we do not have to use every kind coin available.
Example 2:
Input: coins = [2], amount = 3
Output: -1
Explanation: The amount of 3 cannot be made up with coins of 2.
Example 3:
Input: coins = [1], amount = 0
Output: 0
Explanation: Choosing 0 coins is a valid way to make up 0.
Constraints
1 <= coins.length <= 101 <= coins[i] <= 2^31 - 10 <= amount <= 10000
You should aim for a solution with O(n * t) time and O(t) space, where n is the number of coins and t is the given amount.
Solution
Each coin we can use is a branch in a tree. DFS can explore all branches, but there is a lot of duplicate work, so we use memoization.
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
if (amount == 0) { return 0; }
constexpr auto INF = std::numeric_limits<int>::max();
std::unordered_map<int, int> memory;
std::function<int(int)> dfs;
dfs = [&](int amount) -> int {
// Base case
if (amount == 0) { return 0; }
// Previously seen result
if (memory.contains(amount)) { return memory[amount]; }
int result = INF;
for (const auto &coin : coins) {
if (amount - coin >= 0) {
auto res = dfs(amount - coin);
if (res < INF) {
result = std::min(result, res + 1);
}
}
}
memory[amount] = result;
return result;
};
auto result = dfs(amount);
return result == INF ? -1 : result;
}
};