代码随想录day44 动态规划
题518 零钱兑换
1,完全背包问题,因为钱币数量可使用多次,相当于物品可以多次使用。
2,dp数组的含义为凑成 j 数量的钱有dp[j]种组合。
3,此题要注意遍历顺序,一定是外层循环为物品,内层循环为背包,相当于固定一个物品来遍历所有的背包,比如背包容量为4,先取第一个假如容量为1)物品将容量为0-4的背包全部装满(得到一个dp数组),再取第二个物品(假如容量为2)再装一次背包(这一次相当于用两个物品来装背包),依次类推,物品遍历一遍以后就得到了装满0-4的容量的背包的各种组合个数(按照元素也就是物品顺序)。如果将两个for循环顺序颠倒,外层为背包,内层为物品,则相当于用所有的物品来将容量为0-4的背包依次装满,比如装到容量为3的背包时,取物品1(假如容量为1),则会出现(2,1)组合(有2是因为dp[3] += dp[3-1(物品1的容量)],(2)这个组合是dp[2]的),当取到物品2(假如容量为2)时,会出现(1,2)组合,其实这样的颠倒适合求解排列问题(下一题)。
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount + 1];
dp[0] = 1;
for(int i = 0; i < coins.length; i++) {
for(int j = coins[i]; j < amount + 1; j++) {
dp[j] = dp[j] + dp[j - coins[i]];
}
}
return dp[amount];
}
}
题377 组合总和iv
1,本题要求相同元素不同顺序算两个组合,那就是求排列问题。解题思路基本和上一题一样,只是两层for循环的顺序要反过来,外层for循环为背包, 内层为物品。
class Solution {
public int combinationSum4(int[] nums, int target) {
int[] dp = new int[target + 1];
dp[0] = 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]];
}
}
System.out.println(Arrays.toString(dp));
}
return dp[target];
}
}