70. 爬楼梯(进阶)
完成
思路:
之前做过爬楼梯,每次只爬1阶或2阶,本题可以爬1~m阶楼梯。可以转化为完全背包问题,为什么不是01背包呢?因为每个台阶层数都可以多次选择。
楼梯的总台阶数就是背包容量,每次爬的台阶就是物品的重量,要求把背包装满有多少种方法。其实也是排列问题,因为对于3阶台阶而言,1、2与2、1是两种方法,都要算进去。
排列问题需要先遍历背包,再遍历物品。
代码
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner in = new Scanner(System.in);
int n = in.nextInt();
int m = in.nextInt();
int[] dp = new int[n+1];
dp[0] = 1;
for(int j=1; j<=n; j++){ // 先遍历背包
for (int i=1; i<=m; i++){
if(j>=i) dp[j] += dp[j-i];
}
}
System.out.println(dp[n]);
}
}
322. 零钱兑换
完成
思路:
本题可以把总金额看成背包容量,硬币就是物品,其价值就是重量。题目要求凑成总金额所需的最少硬币数量,dp[j]
代表装满容量为j
的背包,最少的物品数量为dp[j]
。
递推公式为dp[j] = Math.min(dp[j], dp[j-coins[i]]+1)
,由于是取最小,初始化就不能为0了,否则会污染计算出的数据,但是dp[0]需要是0。另外需要注意,本题并不是一定能取到总金额,还有不成立的情况。
代码
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 = coins[i]; j <= amount; j++) {
// 这个if条件一定要加,只有当条件成立,取值才有意义
// 否则,dp[j-coins[i]]+1 就是 -2147483648
if(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;
return dp[amount];
}
}
279.完全平方数
完成
思路:
和上题一样。
在物品的处理上,可以把i*i
作为物品,但是本题给了范围,也就是物品的最大数量是100,把这100个物品列成数组,可以减少一点计算量。
代码
class Solution {
public int numSquares(int n) {
// 物品
int[] goods = {1,4,9,16,25,36,49,64,81,100,121,144,169,196,225,256,289,324,361,400,441,484,529,576,625,676,729,784,841,900,961,1024,1089,1156,1225,1296,1369,1444,1521,1600,1681,1764,1849,1936,2025,2116,2209,2304,2401,2500,2601,2704,2809,2916,3025,3136,3249,3364,3481,3600,3721,3844,3969,4096,4225,4356,4489,4624,4761,4900,5041,5184,5329,5476,5625,5776,5929,6084,6241,6400,6561,6724,6889,7056,7225,7396,7569,7744,7921,8100,8281,8464,8649,8836,9025,9216,9409,9604,9801,10000};
int[] dp = new int[n+1];
dp[0] = 0;
for (int i = 1; i <= n; i++) {
dp[i] = Integer.MAX_VALUE;
}
for (int i = 0; i < goods.length; i++) {
// 剪枝
if(goods[i]>n) break;
for (int j = goods[i]; j <= n; j++) {
dp[j] = Math.min(dp[j], dp[j-goods[i]]+1);
}
}
return dp[n];
}
}