给你一个整数数组 coins
表示不同面额的硬币,另给一个整数 amount
表示总金额。
请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0
。
假设每一种面额的硬币有无限个。
题目数据保证结果符合 32 位带符号整数。
示例 1:
输入:amount = 5, coins = [1, 2, 5] 输出:4 解释:有四种方式可以凑成总金额: 5=5 5=2+2+1 5=2+1+1+1 5=1+1+1+1+1
示例 2:
输入:amount = 3, coins = [2] 输出:0 解释:只用面额 2 的硬币不能凑成总金额 3 。
示例 3:
输入:amount = 10, coins = [10] 输出:1
提示:
1 <= coins.length <= 300
1 <= coins[i] <= 5000
coins
中的所有值 互不相同0 <= amount <= 5000
算法分析:
题目描述钱硬币数目不限,所以这道题是一道完全背包问题。
物品就是硬币的面额,而背包容量就是总金额。
按照动规五部曲来。
dp[j]表示金额为j的总额所能凑成的硬币组合数。
dp[j]+=dp[j-coins[i],现有面额为coins[i]的硬币,那么总额为j的组合数可由总额为j-coins[i]的组合数推到而来。
dp[0]初始化为1,乳沟初始化为0,后面所有情况都会变成0。
注意这里要求的是凑成总额的不同硬币的组合数,不强调元素之间的顺序。
例如:3=2+1,3=1+2是同一种情况。如果要求的是排列数那么就是两种情况。
所以这里要注意对物品和背包容量的遍历顺序。
如果要求的是组合数,那么先遍历物品在遍历容量(对于每种容量,无论每种物品取多少,但取每种物品的顺序是不会改变的),如果要求的是排列数,那么先遍历容量在遍历物品(对于每种容量,去物品的顺序肯能会改变)。
如果结果有误,可以打印dp数组来进行验证。
代码如下:
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;//初始化为1
for(int i = 0; i < coins.length; i++) {//遍历不同面额的硬币
for(int j = coins[i]; j <= amount; j++) {//遍历总金额
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}
}
给你一个由 不同 整数组成的数组 nums
,和一个目标整数 target
。请你从 nums
中找出并返回总和为 target
的元素组合的个数。
题目数据保证答案符合 32 位整数范围。
示例 1:
输入:nums = [1,2,3], target = 4 输出:7 解释: 所有可能的组合为: (1, 1, 1, 1) (1, 1, 2) (1, 2, 1) (1, 3) (2, 1, 1) (2, 2) (3, 1) 请注意,顺序不同的序列被视作不同的组合。
示例 2:
输入:nums = [9], target = 3 输出:0
提示:
1 <= nums.length <= 200
1 <= nums[i] <= 1000
nums
中的所有元素 互不相同1 <= target <= 1000
进阶:如果给定的数组中含有负数会发生什么?问题会产生何种变化?如果允许负数出现,需要向题目中添加哪些限制条件?
这道题和上道题一样都是完全背包问题,不同的是上道题求的是凑成总金额的组合数,而这道题是组成不目标整数的排列数(强调顺序可以改变)。
所以遍历的时候我们需要先遍历背包容量再遍历物品。
dp[j]表示凑成目标整数j的不同序列数有dp[j]种。
dp[j]+=dp[j-nums[i]],现有数nums[i]那么凑成j的序列数dp[j]可由j-nums[i]的序列数推导而出。
dp[0]=1,之后的每种情况都有它推导而来,所以置为1。
因为是求排列数,情调元素的顺序,所以先遍历背包容量(也即目标整数),在遍历物品(每个元素)。
可以打印dp数组进行验证。
代码如下:
class Solution {
public int combinationSum4(int[] nums, int target) {
int[] dp = new int[target + 1];
dp[0] = 1;//初始化1
for(int j = 0; j <= target; j++) {//遍历目标整数
for(int i = 0; i < nums.length; i++) {//遍历每个元素
if(j >= nums[i]) {
dp[j]+=dp[j-nums[i]];
}
}
}
return dp[target];
}
}
这两道题是完全背包问题的两种不同求法。