table of Contents
1. Topic
- Change exchange
given coins of different denominations of coins and a total amount of amount. We can write a function to calculate the minimum number of coins needed to make up the total amount. If there is no combination can be composed of any of a total amount of coins, return -1.
Example 1:
Input: coins = [1, 2, 5], amount = 11
Output: 3
Explanation: 11 = 5 + 5 + 1
Example 2:
Input: coins = [2], amount = 3
Output: -1
Note:
You can think of each coin number is unlimited.
2. Solution
2.1. Brute force
Brute force is the essence of a program a try, if the conditions are met that the number of coins used in the record, and then from the minimum value.
2.1.1. Brute force 1
Note: do not need to be exhaustive of all combinations, the combination of large numbers beginning, a number of coins is determined as the minimum effective combination filter can reduce the number of recursive invalid;
coinChange_1 DEF (Self, Coins, AMOUNT): "" " brute force recursion def _helper (coins, num, leftamount , cur_coins_list): recursive function, coins: coin pool; num: subscript; leftamount: remaining amount of money; cur_coins_list: sequence current coin time complexity: O (S ^ N); because each coin may have up to the worst case S / Ci one; therefore the number of possible combinations of S / C1 * S / C2 * S / C3 ... ... S / Cn = S ^ N / C1 * C2 * C3 ...... Cn simplify what is ^ N S S is the amount, N is the number of coin types. space complexity: O (N) worst case , the maximum depth of recursion is N. : param coins: : param AMOUNT: : return: "" " Assert and coins None Not AMOUNT iS> 0, 'error value.' mincount AMOUNT +. 1 = # coins sorted by inversion large to small Coins = List (the reversed (Coins )) # 递归函数 def _helper(coins, num, leftamount, cur_coins_list): nonlocal mincount cur_coins_list.append(coins[num]) length = len(cur_coins_list) if leftamount == 0: if length < mincount: mincount = length elif leftamount > 0: if length >= mincount: return for i in range(num, len(coins)): _helper(coins, i, leftamount-coins[i], cur_coins_list[:]) for x in range(len(coins)): _helper(coins, x, amount - coins[x], []) return -1 if mincount > amount else mincount
2.1.2. Brute force 2
The same logic, another way.
def coinChange_1_1(self, coins, amount): """ 暴力穷举 :param coins: :param amount: :return: """ coins = list(reversed(coins)) def _helper(index, coins, amount): if amount == 0: return 0 if index < len(coins) and amount > 0: mincost = float('inf') for i in range(0, amount//coins[index]+1): if amount >= i * coins[index]: res = _helper(index+1, coins, amount - i * coins[index]) if res != -1: mincost = min(mincost, res+i) return -1 if mincost == float('inf') else mincost return -1 return _helper(0, coins, amount)
2.2. Bottom-up dynamic programming -1
One-dimensional array defined DP
DP [I] is a combination of the minimum number of coins required when as i, is then pushed forward to continue dp [i] = dp + 1 the minimum number of coins required [i-coin [j]] , +1 for using a coin [j] once.
principle:
Definition array dp [i] [j], it is the number of coins, the total amount of j, if j is defined as where element may be made of coins [0-i] in the composition of the coin, the coin is composed of a desired number of programs minimum. Provided dp [x] [y] solution exists, then dp [x] [y-coin [x]] least one solution (unless y is less than X), and dp [x] [y] of possible values dp [x] [y-coin [x]] + 1 ( the basis of the former added an extra coin [x]) , however, note that the column j for all solutions in this amount on behalf of, so if dp [x-1] [y ] exists Solutions , means that the solution to the dp [x] [y] is also effective. Subject of the request is the minimum number of coins solution, it takes a minimum value both of: DP [X] [Y] = min (DP [X] [Y-COIN [X]], DP [. 1-X] [Y ]) of course, this is a two-dimensional array, but in practice is not concerned [x-2] and the data of the previous lines, but one by one backward iteration, it is possible to multiplex one-dimensional array is simplified.
Code:
def coinChange_2(self, coins, amount): """ 动态规划 从下至上 :param coins: :param amount: :return: """ dp = [float('inf')] * (amount + 1) dp[0] = 0 for coin in coins: for x in range(coin, amount + 1): dp[x] = min(dp[x], dp[x-coin] + 1) return dp[amount] if dp[amount] != float('inf') else -1
2.3 top-down dynamic programming -2
Variant of the recursive method, using an array of records has been seeking solutions.
def coinChange_2_2(self, coins, amount): """ 动态规划/递归穷举/回溯法 自上而下 :param coins: :param amount: :return: """ def _helper(coins, leftamount, count_list): if leftamount < 0: return -1 if leftamount == 0: return 0 if count_list[leftamount-1] != 0: return count_list[leftamount - 1] mincount = float('inf') for x in range(len(coins)): res = _helper(coins, leftamount - coins[x], count_list) if res >= 0 and res < mincount: mincount = res + 1 count_list[leftamount - 1] = mincount if mincount != float('inf') else -1 return count_list[leftamount - 1] return _helper(coins, amount, [0]*amount)
3. Code and test results
3.1 test code:
the __name__ == IF "__main__": # instance solutions based SO = Solution () # Parameter setting Li = [1,2,5,10,20] para = (Li, 1 18) test_func (SO, para) Pass
3.2 Results:
A total of <4> of the method: [ 'coinChange_1_1', 'coinChange_1_2', 'coinChange_2_1', 'coinChange_2_2'] ************************************************************ *************** the method of [1]: coinChange_1_1 Description: brute force recursion def _helper (coins, num, leftamount , cur_coins_list): recursive function, coins: coin pool; NUM: at standard; leftamount: remaining amount of money; cur_coins_list: sequence current coin time complexity: O (S ^ N); because each coin may have up to S / Ci a worst case; it may be the number of combinations of S / C1 * S / C2 * S / C3 ...... S / Cn = S ^ N / C1 * C2 * C3 ...... Cn simplify what is ^ N S S is the amount, N is the number of coin types. Space complexity: worst case O (N), the maximum depth of recursion is N. : param Coins is: : param AMOUNT: : return: Description: brute force : param Coins is: : param AMOUNT: : return: The results: 9 ************************************** ** the method of [3]: coinChange_2_1 Description: dynamic programming from bottom to top : param Coins: : param AMOUNT: : return: the results: 9 ******************** ******************** The method of [4]: coinChange_2_2 Description: dynamic programming / recursive exhaustive / backtracking from top to bottom : param Coins: : param AMOUNT: : return: The results: 9 length performed: ( 'coinChange_1_1', .0018791932531923659) ( 'coinChange_1_2', .10514478138982856) ( 'coinChange_2_1', .00021833724987438408) ( 'coinChange_2_2', .0006242205989998584) Process Finished Exit with code 0