LintCode刷题——换硬币
题目描述:
给出不同面额的硬币以及一个总金额. 写一个方法来计算给出的总金额可以换取的最少的硬币数量. 如果已有硬币的任意组合均无法与总金额面额相等, 那么返回 -1
.
样例
样例1
输入:
[1, 2, 5]
11
输出: 3
解释: 11 = 5 + 5 + 1
样例2
输入:
[2]
3
输出: -1
注意事项
你可以假设每种硬币均有无数个
总金额不会超过10000
硬币的种类数不会超过500, 每种硬币的面额不会超过100
思路:序列型动态规划
1、定义状态:dp[i] 表示拼出面值为i需要的最少硬币数
2、转移方程:dp[i] = min{dp[i], dp[i - coins[j]]+ 1}
3、初始值和边界:dp[0] = 0,为啥这里等于0,后面拼不出却设置为无穷大呢,其实这是有一定道理的,因为现实中,0是可以拼出来的,因为不给硬币即可做到,后面设置为无穷大是为了从中选出方案中最小的硬币数
4、计算返回dp[amount] ,不过题目明确说了,如果拼不出,则返回-1,所以最后还需再稍稍处理一下即可
AC代码:
1 public class Solution { 2 /** 3 * @param coins: a list of integer 4 * @param amount: a total amount of money amount 5 * @return: the fewest number of coins that you need to make up 6 */ 7 public int coinChange(int[] coins, int amount) { 8 // write your code here 9 if (coins == null || coins.length == 0) { 10 // 这还需要判断一下,因为可能你没有候选的硬币数,但是要让你拼出大于0的数,那么就拼不出了 11 if (amount <= 0) { 12 return 0; 13 } else { 14 // 这里的意思,其实就是说:比如你去店里买东西,忘了带钱,你身上一分都没 15 // 但是老板依然让你给钱,不给不能走,此时的场景就好比你无论如何也拼不出的情况 16 return -1; 17 } 18 } else { 19 // 如果存在硬币,但要拼的却是0,可以直接返回0即可 20 if (amount == 0) { 21 return 0; 22 } 23 } 24 25 // 定义状态:dp[i] 表示拼出面值为i需要的最少硬币数 26 int[] dp = new int[amount + 1]; 27 28 // 初始化 29 dp[0] = 0; 30 31 // 转移方程 ,这里要从1开始,因为0在前面已经做了相关处理 32 // 现实中,0是可以拼出来的,因为不给硬币即可做到 33 for (int i = 1; i <= amount; i++) { 34 // 默认一开始都是拼不出来,这里将拼不出设置为无穷大 35 dp[i] = Integer.MAX_VALUE; 36 // 子问题:随便拿一个面值的硬币,将剩下的面值数交给更小的子问题去完成 37 // 如果此时要拼的面值小于此时拿的一个硬币的面值,那么就不拿这个硬币,换下一个硬币 38 // 且要保证剩下的面值数是能拼的出来的才行 39 // 枚举所有硬币 40 for (int j = 0; j < coins.length; j++) { 41 if (i >= coins[j] && dp[i - coins[j]] != Integer.MAX_VALUE) { 42 // 如果此时拿的硬币满足以上限制条件,那么就从满足条件的这些方案中选出拿硬币最少的 43 // 如果当前的方案比之前的更好,则更新 44 dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1); 45 } 46 } 47 } 48 49 // 返回结果,这里由于题目的要求,所以不能直接返回,要稍微做下处理,如果拼不出,则返回-1 50 if (dp[amount] == Integer.MAX_VALUE) { 51 return - 1; 52 } 53 return dp[amount]; 54 } 55 }