58 lines
1.8 KiB
Ruby
58 lines
1.8 KiB
Ruby
|
# dynamic programming version
|
||
|
def make_change(amount, coins)
|
||
|
result = Array.new(amount + 1, 0)
|
||
|
result[0] = 1
|
||
|
|
||
|
coins.each do |coin|
|
||
|
(coin..amount).each do |higher_amount|
|
||
|
remainder = higher_amount - coin
|
||
|
result[higher_amount] += result[remainder]
|
||
|
end
|
||
|
end
|
||
|
|
||
|
result[amount]
|
||
|
end
|
||
|
|
||
|
# recursive version:
|
||
|
def make_change2(target, coins = [25, 10, 5, 1])
|
||
|
return [] if target == 0
|
||
|
return nil if coins.none? { |coin| coin <= target }
|
||
|
|
||
|
coins = coins.sort.reverse
|
||
|
|
||
|
best_change = nil
|
||
|
coins.each_with_index do |coin, index|
|
||
|
# can't use this coin, it's too big
|
||
|
next if coin > target
|
||
|
|
||
|
# use this coin
|
||
|
remainder = target - coin
|
||
|
|
||
|
# Find the best way to make change with the remainder (recursive
|
||
|
# call). Why `coins.drop(index)`? This is an optimization. Because
|
||
|
# we want to avoid double counting; imagine two ways to make
|
||
|
# change for 6 cents:
|
||
|
# (1) first use a nickel, then a penny
|
||
|
# (2) first use a penny, then a nickel
|
||
|
# To avoid double counting, we should require that we use *larger
|
||
|
# coins first*. This is what `coins.drop(index)` enforces; if we
|
||
|
# use a smaller coin, we can never go back to using larger coins
|
||
|
# later.
|
||
|
best_remainder = make_change2(remainder, coins.drop(index))
|
||
|
|
||
|
# We may not be able to make the remaining amount of change (e.g.,
|
||
|
# if coins doesn't have a 1cent piece), in which case we shouldn't
|
||
|
# use this coin.
|
||
|
next if best_remainder.nil?
|
||
|
|
||
|
# Otherwise, the best way to make the change **using this coin**,
|
||
|
# is the best way to make the remainder, plus this one coin.
|
||
|
this_change = [coin] + best_remainder
|
||
|
|
||
|
# Is this better than anything we've seen so far?
|
||
|
best_change = this_changeif best_change.nil? || this_change.count < best_change.count
|
||
|
end
|
||
|
|
||
|
best_change
|
||
|
end
|