背包问题
70.爬楼梯
解题思路:
- 斐波那契数列 --- dp[i] = dp[i-1] + dp[i-2]
- 完全背包问题: 假设物品有两个 (一步和两步), 每种物品无限个, 现问装完背包为n的可以有多少种不同的方案?
- 完全背包: 求不同排列, 故外层背包, 内层物品, 背包升序遍历, 递推公式为dp[j] = dp[j] + dp[j-i]
代码:
class Solution {
// 假设背包容量为n, 物品有两个1和2, 每种物品有无限个
// 请问背包装满的所有情况
// 同时 先走1再走2 和先走2再走1 是两种不同的情况, 所以是求排列?
public int climbStairs(int n) {
int[] dp = new int[n + 1];
dp[0] = 1;
// 完全背包 --- 升序 --- 求排列:背包在外层遍历
for(int j=1; j <= n; j++){
// 遍历物品
for(int i=1; i<=2; i++){
if(i <= j)
dp[j] = dp[j] + dp[j-i];
}
}
return dp[n];
}
}
322.零钱兑换
解题思路: 硬币无限个, 完全背包问题
- 求最少硬币个数, 假设硬币价值为1, 此题即求装满背包的最小价值
- 求组合问题, 故外层遍历物品, 内层遍历背包
- 求最小价值, 且元素初始化为最大值, 并且dp[0] 初始化成0
代码:
class Solution {
// 假设物品价值为1, 求最少的物品个数即就是求装满背包的最小价值
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount+1];
Arrays.fill(dp, 0x7fffffff);
dp[0] = 0;
// 完全背包问题 --- 求最小价值 --- 求组合
for(int i=0; i<coins.length; i++){
for(int j=coins[i]; j<=amount; j++){
if(dp[j-coins[i]] != 0x7fffffff){
dp[j] = Math.min(dp[j], dp[j-coins[i]] + 1);
}
}
}
// -1: 装不满背包
return dp[amount] == 0x7fffffff ? -1:dp[amount];
}
}
279.完全平方数
解题思路:
- 每个物品是完全平方数, 其为小于n的完全平方数
- 可以无限拿, 所以是完全背包问题
- 且求组和, 所以是外层物品, 内层背包
- 求最少个数, 假设物品价值为1, 即装满背包的最小价值
- 因为本题有1, 所以肯定能装满, 无需考虑装不满的情况
代码:
class Solution {
// 因为本题有1, 所以肯定能装满, 无需考虑装不满的情况
public int numSquares(int n) {
// 完全背包问题 --- 求最小价值 --- 求组和(外层物品 & 内层背包)
int[] dp = new int[n + 1];
Arrays.fill(dp, 0x7fffffff);
dp[0] = 0;
// 遍历物品
for(int i=1; i*i <= n; i++){
// 遍历背包
for(int j=i*i; j<=n; j++){
dp[j] = Math.min(dp[j], dp[j-i*i] + 1);
}
}
return dp[n];
}
}