70. 爬楼梯 (进阶)
思路:
完全背包(前向后更新dp[i])求排列(先循环背包)问题。
代码:
class Solution {
public int climbStairs(int n) {
int[] dp = new int[n + 1];
dp[0] = 1;
int[] weight = {1,2};//相当于物品的价值
//相当于求排列,先循环背包
for(int i = 1; i <= n; i++){
for(int j = 0; j < weight.length; j++){
if(i >= weight[j]){
dp[i] += dp[i - weight[j]];
}
}
}
return dp[n];
}
}
需要注意的点:
322. 零钱兑换
思路:
完全背包,可重复组合数,但求最小值,需要更新(用min)
代码:
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount + 1];
int max = Integer.MAX_VALUE;
//递推公式性质(求最小值),所以非零下标初始化为较大的值,防止结果被小的初始值覆盖
for(int i = 1; i <= amount; i++){
dp[i] = max;
}
//求组合数,先循环物品
for(int i = 0; i < coins.length; i++){
for(int j = coins[i]; j <= amount; j++){
if(dp[j - coins[i]] != max){//只有前面背包不空才能推导现在的状态
dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
}
}
}
return dp[amount] == max ? -1 : dp[amount];
}
}
需要注意的点:
1、初始化,非零下标要设为较大的值,否则求最小值容易被初始dp[j]覆盖。
2、只有当前一个状态的方法数更新过(不为max)才能在本状态利用(更新)。
3、求所含元素的最小个数,组合、排列的循环方法都可以。
279.完全平方数
思路:
和上一道题类似,因为求最小组合数,有没有顺序都不影响钱币的最小个数。物品相当于是i*i,一直到背包的容量。
代码:
class Solution {
public int numSquares(int n) {
int[] dp = new int[n + 1];
int max= Integer.MAX_VALUE;
for(int i = 1; i <= n; i++){
dp[i] = max;
}
for(int j = 1; j <= n; j++){
for(int i = 1; i * i <= j; i++){
dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
}
}
return dp[n];
}
}