We can see if your code is correct quite easily. let's try making change for a dime. There are four ways: 1 dime, 2 nickels, 1 nickel and 5 pennies, and 10 pennies, yet count_ways(10) #=> 9
.
You can do it as follows, using recursion.
Code
def count_ways(cents, coins)
if coins.size == 1
return (cents % coins.first) == 0 ? [cents/coins.first] : nil
end
coin, *remaining_coins = coins
(0..cents/coin).each_with_object([]) { |n, arr|
count_ways(cents-n*coin, remaining_coins).each { |a| arr << [n, *a] } }
end
Examples
coins = [25, 10, 5, 1]
count_ways(32, coins)
#=> [[0, 0, 0, 32], [0, 0, 1, 27], [0, 0, 2, 22], [0, 0, 3, 17], [0, 0, 4, 12],
# [0, 0, 5, 7], [0, 0, 6, 2], [0, 1, 0, 22], [0, 1, 1, 17], [0, 1, 2, 12],
# [0, 1, 3, 7], [0, 1, 4, 2], [0, 2, 0, 12], [0, 2, 1, 7], [0, 2, 2, 2],
# [0, 3, 0, 2], [1, 0, 0, 7], [1, 0, 1, 2]]
count_ways(100, coins)
#=> [[0, 0, 0, 100], [0, 0, 1, 95], [0, 0, 2, 90], [0, 0, 3, 85], [0, 0, 4, 80],
# [0, 0, 5, 75], [0, 0, 6, 70], [0, 0, 7, 65], [0, 0, 8, 60], [0, 0, 9, 55],
# ...
# [3, 1, 2, 5], [3, 1, 3, 0], [3, 2, 0, 5], [3, 2, 1, 0], [4, 0, 0, 0]]
count_ways(100, coins).size
#=> 242
Explanation
The best way to show how the recursion works is to salt the code with puts statements and then run it against a simple example.
INDENT = 8
@indentation = 0
def indent
@indentation += INDENT
end
def undent
@indentation = [@indentation-INDENT, 0].max
end
def ind
' '*@indentation
end
def count_ways(cents, coins)
puts "#{ind}** entering count_ways with cents=#{cents}, coins=#{coins}"
if coins.size == 1
puts "#{ind}<< returning [cents]=#{[cents]} as coins.size == 1"
undent
end
return [cents] if coins.size == 1
coin, *remaining_coins = coins
puts "#{ind}coin=#{coin}. remaining_coins=#{remaining_coins}"
puts "#{ind}0..cents/coin=#{0..cents/coin}"
arr = (0..cents/coin).each_with_object([]) do |n, arr|
puts "#{ind} n=#{n}, arr=#{arr}"
puts "#{ind} >> calling count_ways(#{cents}-#{n}*#{coin}, remaining_coins)"
indent
aa = count_ways(cents-n*coin, remaining_coins)
puts "#{ind} aa=#{aa}"
aa.each do |a|
arr << [n, *a]
puts "#{ind} arr << [#{n}, *#{a}], arr=#{arr}"
end
puts "#{ind} after all coins, arr=#{arr}"
end
puts "#{ind}<< returning arr=#{arr}"
undent
arr
end
Now let's run count_ways(12, coins)
which should return the four ways of making change for 12
cents: [[0, 0, 0, 12], [0, 0, 1, 7], [0, 0, 2, 2], [0, 1, 0, 2]]
.
count_ways(12, coins)
** entering count_ways with cents=12, coins=[25, 10, 5, 1]
coin=25. remaining_coins=[10, 5, 1]
0..cents/coin=0..0
n=0, arr=[]
>> calling count_ways(12-0*25, remaining_coins)
** entering count_ways with cents=12, coins=[10, 5, 1]
coin=10. remaining_coins=[5, 1]
0..cents/coin=0..1
n=0, arr=[]
>> calling count_ways(12-0*10, remaining_coins)
** entering count_ways with cents=12, coins=[5, 1]
coin=5. remaining_coins=[1]
0..cents/coin=0..2
n=0, arr=[]
>> calling count_ways(12-0*5, remaining_coins)
** entering count_ways with cents=12, coins=[1]
<< returning [cents]=[12] as coins.size == 1
aa=[12]
arr << [0, *12], arr=[[0, 12]]
after all coins, arr=[[0, 12]]
n=1, arr=[[0, 12]]
>> calling count_ways(12-1*5, remaining_coins)
** entering count_ways with cents=7, coins=[1]
<< returning [cents]=[7] as coins.size == 1
aa=[7]
arr << [1, *7], arr=[[0, 12], [1, 7]]
after all coins, arr=[[0, 12], [1, 7]]
n=2, arr=[[0, 12], [1, 7]]
>> calling count_ways(12-2*5, remaining_coins)
** entering count_ways with cents=2, coins=[1]
<< returning [cents]=[2] as coins.size == 1
aa=[2]
arr << [2, *2], arr=[[0, 12], [1, 7], [2, 2]]
after all coins, arr=[[0, 12], [1, 7], [2, 2]]
<< returning arr=[[0, 12], [1, 7], [2, 2]]
aa=[[0, 12], [1, 7], [2, 2]]
arr << [0, *[0, 12]], arr=[[0, 0, 12]]
arr << [0, *[1, 7]], arr=[[0, 0, 12], [0, 1, 7]]
arr << [0, *[2, 2]], arr=[[0, 0, 12], [0, 1, 7], [0, 2, 2]]
after all coins, arr=[[0, 0, 12], [0, 1, 7], [0, 2, 2]]
n=1, arr=[[0, 0, 12], [0, 1, 7], [0, 2, 2]]
>> calling count_ways(12-1*10, remaining_coins)
** entering count_ways with cents=2, coins=[5, 1]
coin=5. remaining_coins=[1]
0..cents/coin=0..0
n=0, arr=[]
>> calling count_ways(2-0*5, remaining_coins)
** entering count_ways with cents=2, coins=[1]
<< returning [cents]=[2] as coins.size == 1
aa=[2]
arr << [0, *2], arr=[[0, 2]]
after all coins, arr=[[0, 2]]
<< returning arr=[[0, 2]]
aa=[[0, 2]]
arr << [1, *[0, 2]], arr=[[0, 0, 12], [0, 1, 7], [0, 2, 2], [1, 0, 2]]
after all coins, arr=[[0, 0, 12], [0, 1, 7], [0, 2, 2], [1, 0, 2]]
<< returning arr=[[0, 0, 12], [0, 1, 7], [0, 2, 2], [1, 0, 2]]
aa=[[0, 0, 12], [0, 1, 7], [0, 2, 2], [1, 0, 2]]
arr << [0, *[0, 0, 12]], arr=[[0, 0, 0, 12]]
arr << [0, *[0, 1, 7]], arr=[[0, 0, 0, 12], [0, 0, 1, 7]]
arr << [0, *[0, 2, 2]], arr=[[0, 0, 0, 12], [0, 0, 1, 7], [0, 0, 2, 2]]
arr << [0, *[1, 0, 2]], arr=[[0, 0, 0, 12], [0, 0, 1, 7], [0, 0, 2, 2], [0, 1, 0, 2]]
after all coins, arr=[[0, 0, 0, 12], [0, 0, 1, 7], [0, 0, 2, 2], [0, 1, 0, 2]]
<< returning arr=[[0, 0, 0, 12], [0, 0, 1, 7], [0, 0, 2, 2], [0, 1, 0, 2]]
=> [[0, 0, 0, 12], [0, 0, 1, 7], [0, 0, 2, 2], [0, 1, 0, 2]]