Recently I challenged my co-worker to write an algorithm to solve this problem:
Find the least number of coins required that can make any change from
Here goes my solution, again in Python and using dynamic programming. First I generate the minimum sequence of coins required for making change for each amount in the range 1..99, and from that result I find the maximum number of coins needed from each denomination:
def min_any_change():
V, C = [1, 5, 10, 25], 99
mxP, mxN, mxD, mxQ = 0, 0, 0, 0
solution = min_change_table(V, C)
for i in xrange(1, C+1):
cP, cN, cD, cQ = 0, 0, 0, 0
while i:
coin = V[solution[i]]
if coin == 1:
cP += 1
elif coin == 5:
cN += 1
elif coin == 10:
cD += 1
else:
cQ += 1
i -= coin
if cP > mxP:
mxP = cP
if cN > mxN:
mxN = cN
if cD > mxD:
mxD = cD
if cQ > mxQ:
mxQ = cQ
return {'pennies':mxP, 'nickels':mxN, 'dimes':mxD, 'quarters':mxQ}
def min_change_table(V, C):
m, n, minIdx = C+1, len(V), 0
table, solution = [0] * m, [0] * m
for i in xrange(1, m):
minNum = float('inf')
for j in xrange(n):
if V[j] <= i and 1 + table[i - V[j]] < minNum:
minNum = 1 + table[i - V[j]]
minIdx = j
table[i] = minNum
solution[i] = minIdx
return solution
Executing min_any_change() yields the answer we were looking for: {'pennies': 4, 'nickels': 1, 'dimes': 2, 'quarters': 3}. As a test, we can try removing a coin of any denomination and checking if it is still possible to make change for any amount in the range 1..99:
from itertools import combinations
def test(lst):
sums = all_sums(lst)
return all(i in sums for i in xrange(1, 100))
def all_sums(lst):
combs = []
for i in xrange(len(lst)+1):
combs += combinations(lst, i)
return set(sum(s) for s in combs)
If we test the result obtained above, we get a True:
test([1, 1, 1, 1, 5, 10, 10, 25, 25, 25])
But if we remove a single coin, no matter what denomination, we'll get a False:
test([1, 1, 1, 5, 10, 10, 25, 25, 25])