Skip to content

Instantly share code, notes, and snippets.

@vascoosx
Last active August 15, 2019 02:48
Show Gist options
  • Select an option

  • Save vascoosx/ebdd108c23d7ef75107e418e8a128124 to your computer and use it in GitHub Desktop.

Select an option

Save vascoosx/ebdd108c23d7ef75107e418e8a128124 to your computer and use it in GitHub Desktop.
coin change problem solver in ruby
# code modified from https://github.com/nelsonic/coin-change-ruby
class Change
def change(amount, available_coins = [100, 50, 25, 10, 5, 1])
@available_coins = available_coins
smallest = @available_coins.min
zeros = [0] * @available_coins.size
solutions = (0...@available_coins.size).map { |n| k = zeros.dup; k[n] = 1; k }
vectors = solutions.dup
visited = Hash[solutions.map { |v| [v, true] }]
scores = Hash[@available_coins.map { |n| [n, 1] }]
optimal_solution = []
until solutions.empty?
coins = solutions.pop
total = coin_sum(coins)
if total == amount
optimal_solution = coins
elsif (amount - total) >= smallest
new_s = vectors.map { |v| sum(coins, v) }.
reject { |v| visited.key?(v) }.
reject { |v| scores.fetch(coin_sum(v), Float::INFINITY) < v.sum }
solutions += new_s
visited = visited.merge(Hash[new_s.map { |s| [s, true]}])
scores = scores.merge(Hash[new_s.map { |v| [coin_sum(v), coins.sum] }])
end
end
Hash[available_coins.zip(optimal_solution)].reject { |k, v| v == 0 }
end
private
def coin_sum(coins)
prod(@available_coins, coins)
end
def prod(a, b)
a.zip(b).reduce(0) { |s, e| s + e.inject(:*) }
end
def sum(a, b)
a.zip(b).reduce([]) { |s, e| s.append(e.sum) }
end
end
# RSPEC Unit Tests:
describe Change do
it "returns [1] for 1" do
expect(subject.change(1)).to eq(1 => 1)
end
it "returns [1, 1, 1, 1] for 4" do
expect(subject.change(4)).to eq(1 => 4)
end
it "returns [5, 1] for 6" do
expect(subject.change(6)).to eq(5 => 1, 1 => 1)
end
it "returns [25, 10, 10, 1, 1, 1] for 48" do
expect(subject.change(48)).to eq(25 => 1, 10 => 2, 1 => 3)
end
it "returns [100, 25, 10, 5, 1, 1] for 142" do
expect(subject.change(142)).to eq(100 => 1, 25 => 1, 10 => 1, 5 => 1, 1 => 2)
end
it "returns [100,100,50,25,10,5,1] for 291" do
expect(subject.change(291)).to eq(100 => 2, 50 => 1, 25 => 1, 10 => 1, 5 => 1, 1 => 1)
end
it "returns [330, 200] for " do
expect(subject.change(530, [500, 330, 250, 200, 167])).to eq(330 => 1, 200 => 1)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment