动态规划中的零钱凑整问题总结

(一)概念

给定一系列拥有不同面值的零钱,使用这些零钱凑出某个特定的面值。

(二)简单示例

给定面值分别为1,4,16,64的硬币,每种硬币有无限个,给定一个N,求组成N最少需要的硬币的数量,若无法组成则返回-1.
python 伪代码如下:
代码

(三) 经典例题

(1)01背包问题

给定n件物品,第i件物品的价值为v[i],体积为w[i],现在我们拥有一个容量为V的背包。
求能获得的最大价值。

定义dp[i][j]表示前i个物品在剩余空间为j的时候,能获得的最大价值。

python伪代码如下:
代码

(2)凑数问题

给定一个nums,和一个target,问能否使用nums中的数凑出target值。

示例
输入:Nums= [1,2,5,5], target = 11
输出: true

python代码如下:
在这里插入图片描述

(3)Leetcode 322 Coin Change

给定一系列的coins,和一个target,现在需要使用这些coins组成target,问最少需要的硬币数是多少?

示例1:
输入:Coins = [1,2,5], target = 11
输出:3

示例2:
输入:Coins = [2], target = 3
输出:-1

class Solution {
    public int coinChange(int[] coins, int amount) {
        
        int[] dp = new int[amount+1]; //dp[0]=0
        for(int i=1;i<=amount;i++)
            dp[i] = Integer.MAX_VALUE;
        for(int i=0;i<coins.length;i++){
            for(int j=0;j<=amount;j++){
                if(j-coins[i]>=0 && dp[j-coins[i]]!=Integer.MAX_VALUE){
                    dp[j] = Math.min(dp[j], dp[j-coins[i]]+1);
                }
            }
        }
        if(dp[amount]==Integer.MAX_VALUE) //没被修改过,说明凑不了
            return -1;
        else
            return dp[amount];
    }
}
(4)Leetcode 518 Coin Change2

给定一系列的coins,和一个target,现在需要使用这些coins组成target,问有多少种不同的组成方法?

示例1:
输入:Coins = [1,2,5], target = 5
输出:4

示例2:
输入:Coins = [2], target = 3
输出:0

class Solution {
    public int change(int amount, int[] coins) {
     //   if(coins == null && amount==0 ) return 1;
        if(coins==null || amount==0) return 1;
        int[] dp = new int[amount+1]; //dp[i]=0
        dp[0]=1;
        for(int i=0;i<coins.length;i++){
            for(int j=1;j<=amount;j++){
                if(j-coins[i]>=0) 
                    dp[j]+=dp[j-coins[i]];
            }
        }
        return dp[amount];
	}
}
(5)Leetcode 494 Target Sum

给定一系列的非负整数,和一个target,现在需要使用这些整数通过加减法组成target,问有多少种不同的组成方法?

示例1:
输入:nums = [1,1,1,1,1], target = 3
输出:5

解释:
-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3

class Solution {
    public int findTargetSumWays(int[] nums, int S) {
        int sum=0;
        for(int i=0;i<nums.length;i++)
            sum+=nums[i];
        if(sum<S) return 0;
        if((sum+S)%2!=0) return 0; //保证下面计算的target为整数
        
        int target = (sum+S)/2;
        int[] dp = new int[target+1];
        dp[0]=1;
        for(int i=0;i<nums.length;i++){
            for(int j=target;j>=nums[i]-1;j--){
                if(j-nums[i]>=0 && dp[j-nums[i]]>0)
                    dp[j] += dp[j-nums[i]];
            }
        }  
        return dp[target];
    }
}
  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
零钱问题是指给定一定面额的硬币,以及一个总金额,求出能够凑出该总金额的最少硬币数。这是一个经典的动态规划问题,可以使用Java语言来实现。 首先,我们需要定义一个函数来解决凑零钱问题。该函数需要接收两个参数:硬币面额数组和目标金额。函数的返回值应该是能够凑出目标金额的最少硬币数。 接下来,我们可以使用一个一维数组来记录每个金额所需要的最少硬币数。数组的长度应该是目标金额加一,因为我们需要计算从0到目标金额的最少硬币数。 然后,我们可以使用一个循环来遍历每个金额,并计算出凑出该金额所需要的最少硬币数。具体的计算方法是:对于每个硬币面额,如果该面额小于等于当前金额,那么就可以使用该硬币来凑出当前金额。此时,我们需要使用之前计算出的最少硬币数来更新当前金额所需要的最少硬币数。具体的更新方法是:将当前金额减去硬币面额,然后加上使用该硬币所需要的最少硬币数。最后,我们需要在所有硬币面额选择最小的硬币数作为当前金额所需要的最少硬币数。 最后,我们可以返回数组最后一个元素作为凑出目标金额的最少硬币数。 下面是Java代码实现: ```java public int coinChange(int[] coins, int amount) { int[] dp = new int[amount + 1]; Arrays.fill(dp, amount + 1); dp[0] = 0; for (int i = 1; i <= amount; i++) { for (int j = 0; j < coins.length; j++) { if (coins[j] <= i) { dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1); } } } return dp[amount] > amount ? -1 : dp[amount]; } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值