Find the least number of coins required that can make any change from 1 to 99 cents

后端 未结 27 2260
生来不讨喜
生来不讨喜 2020-12-07 10:08

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

27条回答
  •  难免孤独
    2020-12-07 10:15

    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])
    

提交回复
热议问题