You are given an integer array coins
representing coins of different denominations and an integer amount
representing a total amount of money.
Return the fewest number of coins that you need to make up that amount. If that amount of money cannot be made up by any combination of the coins, return -1
.
You may assume that you have an infinite number of each kind of coin.
Example 1:
Input: coins = [1,2,5], amount = 11 Output: 3 Explanation: 11 = 5 + 5 + 1
Example 2:
Input: coins = [2], amount = 3 Output: -1
Example 3:
Input: coins = [1], amount = 0 Output: 0
Constraints:
1 <= coins.length <= 12
1 <= coins[i] <= 231 - 1
0 <= amount <= 104
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force approach to solving coin change involves exploring every single possible combination of coins to reach the target amount. It’s like trying every way you can think of to add coins together until you find the right amount. If we find a combination, we record it, and at the end we know the fewest coins we can use.
Here's how the algorithm would work step-by-step:
def coin_change_brute_force(coins, amount):
minimum_number_of_coins = float('inf')
def find_minimum_coins(remaining_amount, current_coin_count):
nonlocal minimum_number_of_coins
if remaining_amount == 0:
minimum_number_of_coins = min(minimum_number_of_coins, current_coin_count)
return
if remaining_amount < 0:
return
# Iterate through each coin denomination
for coin in coins:
# Recursively explore the solution space by subtracting the coin
# from the remaining amount and incrementing the coin count
find_minimum_coins(remaining_amount - coin, current_coin_count + 1)
find_minimum_coins(amount, 0)
# If no combination was found, return -1
if minimum_number_of_coins == float('inf'):
return -1
return minimum_number_of_coins
The best way to figure out the fewest coins needed is to solve smaller problems first and build up to the final answer. Imagine having a chart where each spot represents an amount of money, and we fill it in gradually using only the available coins. This ensures we're reusing previous calculations to avoid redundant work, giving us a quick and efficient final answer.
Here's how the algorithm would work step-by-step:
def coin_change(coins, amount):
minimum_number_of_coins = [float('inf')] * (amount + 1)
minimum_number_of_coins[0] = 0
# Iterate through each coin value
for coin in coins:
# Iterate through each amount from 1 to the target amount
for current_amount in range(1, amount + 1):
# Check if the current coin can be used for the current amount
if coin <= current_amount:
# Update min coins needed using current coin
minimum_number_of_coins[current_amount] = min(
minimum_number_of_coins[current_amount],
1 + minimum_number_of_coins[current_amount - coin]
)
# If no solution, return -1
if minimum_number_of_coins[amount] == float('inf'):
return -1
else:
return minimum_number_of_coins[amount]
Case | How to Handle |
---|---|
coins is null or empty | Return -1 if coins is null or empty, as no coins are available to make up the amount. |
amount is 0 | Return 0 if amount is 0, as no coins are needed. |
coins contains a zero | The algorithm should still function correctly as zero values can contribute to the total amount; however, it may lead to inefficiencies and the algorithm will need to avoid division by zero. |
coins contains negative values | Return an error or throw an exception if coins contains negative values, as negative coin denominations are not physically possible and can lead to infinite loops. |
amount is negative | Return an error or throw an exception if amount is negative, as it is not possible to make up a negative amount. |
No combination of coins can make up the amount | Return -1 if the dynamic programming table's final entry indicates that no solution was found. |
Integer overflow when calculating the minimum number of coins | Use a sufficiently large integer type or check for overflow during calculations, returning a large value (e.g., Infinity in JavaScript, Integer.MAX_VALUE in Java) to represent an impossible solution during intermediate steps. |
Large amount and many coin denominations | Consider optimizing the dynamic programming approach using techniques like memoization or iterative DP to avoid excessive recursion or memory usage. |