卡码网 57 爬楼梯
题目链接:57. 爬楼梯(第八期模拟笔试) (kamacoder.com)
【解题思路】
-
1.确定dp数组下标及其含义:
-
dp[j]表示爬到有j个台阶的楼顶,有dp[j]种方法
-
-
2.确定递推公式
-
dp[j]+=dp[j-i]
-
i代表一步走i个台阶
-
-
-
3.dp数组初始化
-
因为递推公式是累加的公式,所以dp[0]一定为1
-
因为递推公式是累加公式,后面的数字都是由前面推导出来的,所以非0下标元素初始化为0
-
-
4.确定遍历顺序
-
这里是求的排列问题,因此:
-
先遍历背包
-
再遍历物品
-
-
-
5.举例推导dp数组
-
手动推导一下答案,然后将数组打印出来,看看每个状态是否按照我们的思路进行转移
-
-
【解题步骤】
-
1.创建一个dp数组,初始化大小为n+1
-
2.初始化dp[0]=1
-
3.先遍历背包(n)
-
再遍历物品(m)
-
如果j-i大于等于0,说明还没走到顶,还能继续走:
-
递推公式
-
-
-
-
4.输出dp[n]
【代码部分】
import java.util.Scanner;
class climbStairs{
public static void main(String [] args){
Scanner sc = new Scanner(System.in);
int m, n;
while (sc.hasNextInt()) {
n = sc.nextInt();
m = sc.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 >= 0) dp[j] += dp[j - i];
}
}
System.out.println(dp[n]);
}
}
}
LeetCode 322 零钱兑换
题目链接:
【解题思路】
-
1.确定dp数组以及下标含义
-
dp[j]的定义是:装满容量为j的背包最少物品为dp[j]
-
本题最终要求的是dp[amount]
-
-
2.确定递推公式
-
dp[j]=min(dp[j],dp[j-coins[i]]+1)
-
凑足总额为j - coins[i]的最少个数为dp[j - coins[i]],那么只需要加上一个钱币coins[i]即dp[j - coins[i]] + 1就是dp[j](考虑coins[i])
-
-
-
3.确定dp数组如何初始化
-
dp[0]=0
-
dp数组的其他元素初始化为max
-
因为要一直比较选最小的,因此不能初始化为0,只能初始化为int的最大值
-
-
-
4.确定遍历顺序
-
第一种,先遍历物品:
-
再遍历背包:
-
递推公式
-
-
-
第二种,先遍历背包:
-
再遍历物品:
-
递推公式
-
-
-
Carl说先遍历物品是组合数,先遍历背包是排列数,对于这点,我的理解是:
-
先遍历物品后遍历背包:
-
1)外层固定物品1,进入内层循环
-
2)背包容量不断增加
-
物品1被重复添加进不同容量的背包中,直到背包容量遍历完毕
-
-
3)背包容量遍历完毕后,执行下一次循环,开始添加物品2
-
物品1已经被添加进每一个不同容量的背包里,因此物品2肯定会在物品1之后
-
-
-
先遍历背包后遍历物品:
-
1)外层循环固定背包容量
-
在大小固定的背包里循环遍历添加物品,直到物品全遍历一次
-
-
2)物品遍历结束,外层背包容量+1
-
此时仍要执行内层循环,再次遍历一遍物品
-
可能会出现如下情况:
-
在上一轮遍历到物品3时,当前容量的背包已经没有办法塞入物品3,因此背包里此时有物品1和物品2
-
在当前轮遍历的时候发现增加了容量的背包可以再添加一个物品1,就会有【物品1,物品2,物品1】这样的情况,所以很可能会有物品1出现在物品2之类的情况
-
-
-
-
-
-
本题求组合还是求排列都不影响最终结果,因此先遍历物品还是背包都可以
-
-
5.举例推导dp数组
-
手动推导一下答案,然后将数组打印出来,看看每个状态是否是按照我们的思路进行转移的
-
【解题步骤】
-
1.创建一个dp数组,大小为amount+1
-
2.初始化dp数组为最大值,dp[0]=0
-
3.遍历背包和物品:
-
递推公式
-
注意!!!
-
在java中,最大值+1等于最小值!
-
因此在dp[j-coins[i]]执行+1操作前,也就是在递推公式前,需要判断dp[j-coins[i]]是否为最大值,如果为最大值,就没有考虑的必要!!
-
-
-
-
4返回
-
如果dp[amount]==max,说明没有解,return-1
-
如果dp[amount]!=max,返回dp[amount]
-
【代码部分】
class Solution {
public int coinChange(int[] coins, int amount) {
int[] dp = new int[amount+1];
Arrays.fill(dp,Integer.MAX_VALUE);
dp[0] = 0;
for(int i = 0 ; i < coins.length ; i++){
for(int j = coins[i] ; j <= amount ; j++){
if(dp[j-coins[i]] != Integer.MAX_VALUE){
dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
}
}
}
return dp[amount] == Integer.MAX_VALUE?-1:dp[amount];
}
}
LeetCode 279 完全平方数
【解题思路】
解题思路跟上一题几乎一样,只不过把coins[i]换成i*i
【解题步骤】
-
1.创建一个dp数组,大小为n+1
-
2.初始化dp数组为最大值,dp[0]=0
-
3.遍历背包和物品:
-
递推公式
-
注意!!!
-
j需要始终大于i*i,不然没有意义
-
但是不需要用if判断j-i*i下标是否等于max,因为在完全平方数这一题不会有“凑不成”的状况发生
-
-
-
-
4返回
-
returndp[n]
-
【代码部分】
class Solution {
public int numSquares(int n) {
int[] dp = new int[n+1];
Arrays.fill(dp,Integer.MAX_VALUE);
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];
}
}