(一)概念
给定一系列拥有不同面值的零钱,使用这些零钱凑出某个特定的面值。
(二)简单示例
给定面值分别为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];
}
}