Java 求解零钱兑换
Posted 南淮北安
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java 求解零钱兑换相关的知识,希望对你有一定的参考价值。
一、题目
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
你可以认为每种硬币的数量是无限的。
二、完全背包解析
题目要求使用硬币凑总金额,每枚硬币可以使用多次,要求硬币个数最少,所以是完全背包问题,硬币个数最少是组合问题
(1)确定dp数组及下标含义
dp[j] 表示:总金额为 j 时,硬币最少是多少枚
(2)确定递推表达式
对于硬币 coins[i] 存在两种情况,要么放,要么不放,所以有:dp[j],dp[j-coins[i]]+1
所以要求硬币最少的情况为:Math.min(dp[j],dp[j-coins[i]]+1);
这里之所以执行加1操作,是因为这里是求得是硬币数目,如果是求组合个数则不加1,或者也可以认为和初始化时的情况有关
(3)确定初始化情况
dp[0]=0;表示当总金额为0时,需要0枚硬币
同时对于非零的情况初始化为无穷大,因为此时求最小的,不然会被覆盖,同理如果求最大的情况,则初始非零为0
int max = Integer.MAX_VALUE;
//初始化dp数组为最大值
for (int j = 0; j < dp.length; j++)
dp[j] = max;
//当金额为0时需要的硬币数目为0
dp[0] = 0;
(4)确定遍历顺序
本题是求组合的情况,所以可以先遍历物品,再遍历总金额,因为完全背包问题,所以内层循环正序遍历
三、代码
class Solution
public int coinChange(int[] coins, int amount)
int max = Integer.MAX_VALUE;
int[] dp = new int[amount + 1];
//初始化dp数组为最大值
for (int j = 0; j < dp.length; j++)
dp[j] = max;
//当金额为0时需要的硬币数目为0
dp[0] = 0;
for (int i = 0; i < coins.length; i++)
//正序遍历:完全背包每个硬币可以选择多次
for (int j = coins[i]; j <= amount; j++)
//只有dp[j-coins[i]]不是初始最大值时,该位才有选择的必要
if (dp[j - coins[i]] != max)
//选择硬币数目最小的情况
dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
return dp[amount] == max ? -1 : dp[amount];
四、总结
当前情况,可以由上一步的选择推得,所以选择动态规划
动态规划四部曲
每个硬币可以选择多次,所以属于完全背包问题
求组合,对遍历顺序没有要求
由于求组合中硬币最少为多少,所以初始化时非零位初始最大,由于此时初始化为最大,所以这里进行具体选择最小判断时,需要加个if语句判断下,不然会造成越界出现错误
if (dp[j - coins[i]] != max)
//选择硬币数目最小的情况
dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
以上是关于Java 求解零钱兑换的主要内容,如果未能解决你的问题,请参考以下文章