LeetCode322 零钱兑换 动态规划思路及解法

题目:给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。

示例 1:

输入: coins = [1, 2, 5], amount = 11
输出: 3
解释: 11 = 5 + 5 + 1
示例 2:

输入: coins = [2], amount = 3
输出: -1
说明:
你可以认为每种硬币的数量是无限的。

思路:

因为每种硬币可以使用无数次,所以这是一道完全背包问题;
和01背包问题相似,对于一种货币只要条件允许,我可以选择要或者不要,只不过在这道题中,可以要多次;
先构造dp数组:

(1)假定coins数组的长度为n,那么dp数组大小:dp[n][amount + 1];
(2)dp[i][j]的含义是:当前要找的零钱总数是j,当前可以使用的零钱种类是coins[0…i]时,最少的硬币个数(如果可以凑成的话);
(3)dp数组第一行的含义:当零钱只有coins[0]时,对应0~amount这些金额需要多少个硬币,如果无法正好凑成,我们将这个位置设置成正型的最大值,作为判断;
(4)dp数组第一列的含义:当所需金额为0时,不需要任何零钱就可以凑成,所以第一列都是0;
(5)dp[i][j]与两个位置的元素有关系:
当不想或者不能使用当前种类的硬币时:dp[i][j] = dp[i - 1][j];
当使用了当前种类的硬币时:dp[i][j] = dp[i][j - coins[i]] + 1;
这里我们还需要额外的判断,是否无论我当前如何选择,都无法正好凑成需要的钱数;

Java代码:

public static int solution(int[] arr,int aim) {

        int[][] dp = new int[arr.length][aim + 1];
        int max = Integer.MAX_VALUE;
        for(int i = 1; i <= aim; i++) {
            dp[0][i] = max;
            if(i >= arr[0] && dp[0][i - arr[0]] != max) {
                dp[0][i] = dp[0][i - arr[0]] + 1;
            }
        }
        int left = 0;
        for(int i = 1; i < arr.length; i++) {
            for(int j = 1; j <= aim; j++) {
                left = max;
                if(j >= arr[i] && dp[i][j - arr[i]] != max) {
                    left = dp[i][j - arr[i]] + 1;
                }
                dp[i][j] = Math.min(dp[i - 1][j],left);
            }
        }
        return dp[arr.length - 1][aim] == max ? -1 : dp[arr.length - 1][aim];
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值