P
Paolo Bonzini
You aren't trying to make us convert?
No, but I admit I had more interest in GNU Smalltalk's performance
than Ruby's. Still I'm myself interested in Ruby 1.9 and Rubinius
performance.
Paolo
You aren't trying to make us convert?
skeleton:
def make_change(amount, coins = [25, 10, 5, 1])
end
Your function should always return the optimal change with optimal being the
least amount of coins involved. You can assume you have an infinite number of
coins to work with.
24 requires:jonty said:Hi, my solution is a lot simpler than most posted so far
As the aim is to find only the optimum solution all I do is
working with the largest coin first find out the maximum number of
those we can use
and then the next largest and so on which self-evidently is the
optimal solution.
make_change(24, [10,8,2])
Hi, my solution is a lot simpler than most posted so far
As the aim is to find only the optimum solution all I do is
working with the largest coin first find out the maximum number of those
we can use
and then the next largest and so on which self-evidently is the optimal
solution.
Yoan said:24 requires:jonty said:Hi, my solution is a lot simpler than most posted so far
As the aim is to find only the optimum solution all I do is
working with the largest coin first find out the maximum number of
those we can use
and then the next largest and so on which self-evidently is the
optimal solution.
make_change(24, [10,8,2])
2 of coins of value 10
0 of coins of value 8
2 of coins of value 2
where the (self-evidently) optimal solution is:
24 requires:
0 of coins of value 10
3 of coins of value 8
0 of coins of value 2
Cheers,
-- Yoan
I managed to get a solution (which is nil) even for this:
make_change( 2**100-1, (1..100).map{ |n| 2**n } )
I made a slight modification to Paolo's solution, so it avoids
searching coin combinations that are permutations of others (i.e.,
[25, 1] and [1, 25]). It does this by only allowing the system to add
coins at or beyond the last coin used in the combination being built.
So, if the coins are [25, 10, 5, 1], and we're building from 25, 10,
10, 5 then the next coin be only a 5 or a 1. It seems to speed
Paolo's solution by about 30% on my system.
For anyone interested, here are the Australian coin values:
[200, 100, 50, 20, 10, 5] # $2 and $1 are coins. We also have no 1c
or 2c
And in New Zealand we've got rid of the 5c coin too. Just another
example of NZ being ahead of Australia![]()
I'm too lazy to run it... how does it fare for
make_change( 3**100+2, (1..100).map{ |n| 3**n } )
?
make_change(p**10-1, (1..20).map{|n|p**n})
for any prime p (and who can?)
This week's Ruby Quiz is to complete a change making function=85
ruby 1.9.2008/1/27 said:Here is my second attempt:
def make_change(a, list = [25, 10, 5, 1])
# to pass testcases
return nil if a < 0
return nil if a != a.floor
parents = Array.new(a + 1)
parents[0] = 0
worklist = [0]
while parents[a].nil? && !worklist.empty? do
base = worklist.shift
list.each do |coin|
tot = base + coin
if tot <= a && parents[tot].nil?
parents[tot] = base
worklist << tot
end
end
end
return nil if parents[a].nil?
result = []
while a > 0 do
parent = parents[a]
result << a - parent
a = parent
end
result.sort!.reverse!
end
parents[a] is nil if the solution for amount "a" has not been found
yet, and a-c if the solution is the same as the solution for amount "a-
c" plus a coin of value "c". The solution is reconstructed in the
second while loop.
My first solution used an 1.upto(a) loop to compute the optimal
solution for make_change(1), then for make_change(2), etc. This was a
classic dynamic programming style where lower-cost solutions replace
older ones as they are found. In this solution, instead of computing
subproblem solutions in order of amount, I compute solutions in order
of cost: first all solutions of cost 1, then all solutions of cost 2,
etc., until the solution is found for the requested amount (see the
parents[a].nil? test). It is interesting that in this way we don't
even need to store the solutions' costs.
The worst case is when there's no solution and it has cost O(a |
list|). I didn't make any attempt at optimizing it.
The performance is good; vsv's testcases run in 10 seconds (compared
to 30 for my 1.upto(a) solution).
I tried running a similar program in GNU Smalltalk and the results
were disappointing for Ruby 1.8: GNU Smalltalk was about 10 times
faster for this solution, and 18 times faster for the slower
solution. The ratio goes down from 18 to 10 probably because variable-
size collection in Smalltalk require an OrderedCollection, which is
written in 100% Smalltalk (unlike Ruby's Arrays and Smalltalk's fixed-
size Arrays). I'd be very interested if people ran it under Ruby 1.9
or Rubinius and gave times for it.
Paolo
these are the results of vsv's tests and your script with ruby 1.8.6 and
at what the fastest strategies have been.
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.