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

(一)概念

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

(二)简单示例

给定面值分别为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];
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值