卡码网:57. 爬楼梯(opens new window)
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬至多m (1 <= m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
输入描述:输入共一行,包含两个正整数,分别表示n, m
输出描述:输出一个整数,表示爬到楼顶的方法数。
输入示例:3 2
输出示例:3
提示:
当 m = 2,n = 3 时,n = 3 这表示一共有三个台阶,m = 2 代表你每次可以爬一个台阶或者两个台阶。
此时你有三种方法可以爬到楼顶。
使用完全背包
完全背包:同一个物品可以无限次使用
背包 n 物品 0~m
使用0~m 达到背包容量j 有多少种方法’
这道题求的是顺序数,需要考虑背包和物品的顺序,应该是先背包后物品
动规五部曲,很快的写出解题思路
1确定dp数组以及对应下标的含义
使用0~m ,dp[j] 到达j层阶梯有多少种方法
2确定递推公式
dp[j]=dp[j-m]+dp[j]
3dp数组初始化
dp[0]=1 一切的起源
4确定遍历顺序
从前往后
先背包后物品 因为需要考虑顺序
5手动推导dp数组
6打印dp数组
求排列,我之前写成求组合了
排列是要考虑顺序的,组合不需要考虑顺序
import java.util.*;
import java.lang.*;
public class Main{
public static void main (String[] args) {
/*
本题看起来是一道简单题目,稍稍进阶一下其实就是一个完全背包!
如果我来面试的话,我就会先给候选人出一个 本题原题,看其表现,如果顺利写出来,进而在要求每次可以爬[1 - m]个台阶应该怎么写。
顺便再考察一下两个for循环的嵌套顺序,为什么target放外面,nums放里面。
这就能考察对背包问题本质的掌握程度,候选人是不是刷题背公式,一眼就看出来了。
这么一连套下来,如果候选人都能答出来,相信任何一位面试官都是非常满意的。
本题代码不长,题目也很普通,但稍稍一进阶就可以考察完全背包,而且题目进阶的内容在leetcode上并没有原题,一定程度上就可以排除掉刷题党了,简直是面试题目的绝佳选择!
*/
//Dp数组的定义和每个下标的含义
//完全背包,可以选择自己
// weight[m]=[1,2,3...m]
// j 代表到达j有多少种方法
//dp[j] 爬到i层有多少中方法
//确定递推公式
// dp[j] += dp[j-nums[i]];
//dp数组初始化
// dp[0]=1
//确定遍历顺序
//从前往后,从nums[i]开始
//举例推导dp数组
Scanner sc = new Scanner(System.in);
//n 为楼顶
int n = sc.nextInt();
// m 为一步最远的
int m = sc.nextInt();
int[] weight = new int[m+1];
for(int i=1;i<=m;i++){
weight[i] = i;
}
int dp[] = new int[n+1];
dp[0]=1;
// 这道题是求排列,所以我下面的顺序是错的,我这个顺序是求组合
/*for(int i=1;i<=m;i++){
for(int j=weight[i];j<=n;j++){
dp[j]+=dp[j-weight[i]];
}
}*/
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]);
}
}
力扣题目链接(opens new window)
给定不同面额的硬币 coins 和一个总金额 amount。编写一个函数来计算可以凑成总金额所需的最少的硬币个数。如果没有任何一种硬币组合能组成总金额,返回 -1。
你可以认为每种硬币的数量是无限的。
示例 1:
示例 2:
示例 3:
示例 4:
示例 5:
提示:
可以凑成总金额所需的最少的硬币个数
最小值应该怎么处理呢?没想到思路
动规五部曲,很快的写出解题思路
1确定dp数组以及对应下标的含义
使用0~m ,dp[j] 可以凑成总金额所需的最少的硬币个数
2确定递推公式
是否选中当前, 若选中则dp[j-coins[i]]+1
dp[j]=Math.min(dp[j],dp[j-coins[i]]+1)
3dp数组初始化
dp[0]=0,其他都为Integer.MAX_VALUE
4确定遍历顺序
从前往后
不需要考虑组合或排列,只是求最小值而已
5手动推导dp数组
6打印dp数组
从dp[j]的定义来入手考虑递推公式,比如这道题dp[j]代表可以凑成总金额所需的最少的硬币个数,则递推公式为 ,要么选中当前物品 则为dp[j-coins[i]]+1 ,要么不选,则为dp[j](之前的值)
求最小值,应该把其他元素都设为Integer.MAX_VALUE ,第一个元素为0
class Solution {
public int coinChange(int[] coins, int amount) {
//每次取最小值?
//dp[i] 代表凑成总金额所需的硬币数目
// 比如nums[0]=1 amount = 100 凑成1 需要dp[0]+1 or dp[1] 中的最小值
// 则凑成100 需要 dp[99]+1 or dp[100] 的最小值 ,dp[100-1] = dp[99]
// dp数组的定义和下标的含义
// 可以凑成j金额的最少硬币个数
// 确定递推公式
// 0~i凑成j金额的个数 每凑成一个+1
// dp[j] = Math.min(dp[j-coins[i]]+1,dp[j])
// dp数组初始化
// dp[0] = 0,由于是凑成最小个数,则除开第一个外,其他的都是max
// 确定遍历顺序
// 举例推导dp数组
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
力扣题目链接(opens new window)
给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。
给你一个整数 n ,返回和为 n 的完全平方数的 最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
示例 1:
示例 2:
提示:
和上一题感觉差不多,也是求最小数量
但物品为 各个数的平方,1 4 9 16.。。 要怎么来遍历?
其实是用for循环来控制
动规五部曲,很快的写出解题思路
1确定dp数组以及对应下标的含义
dp[j] 和为j的完全平方数的最小数量
2确定递推公式
是否选中当前, 若选中则dp[j-coins[i]]+1
dp[j]=Math.min(dp[j],dp[j-i]+1)
3dp数组初始化
dp[0]=0,其他都为Integer.MAX_VALUE
4确定遍历顺序
从前往后
不需要考虑组合或排列,只是求最小值而已
5手动推导dp数组
6打印dp数组
按照for循环来确立物品的范围
先背包后物品
for(int i=1;i<=n;i++){
//物品的平方要<=i
for(int j=1;j*j<=i;j++){
}
}
先物品后背包
for(int i=1;i*i<=n;i++){
//物品的平方要<=i
for(int j=1;j<=m;j++){
}
}
求最小值,应该把其他元素都设为Integer.MAX_VALUE ,第一个元素为0
class Solution {
public int numSquares(int n) {
//完全平方数和为背包容量j
// 在完全平方数中选取能满足完全平方数和为背包容量j的最小个数
// dp数组的定义和下标的含义
// dp[j]为能满足容量j所需的完全平方数的最小个数
// 确定递推公式
// dp[j]=Math.min(dp[j],dp[j-某个平方]+1);
// dp数组初始化
// dp[0]=0,其他都为最大值
// 确定遍历顺序
// 可以重复使用,则从前往后
// 举例推导dp数组
// 平方为1 dp[0]=0,dp[1]=1;dp[2]=2;dp[3]=3;dp[4]=4;
// 平方为4 dp[0]=0,dp[1]=1;dp[2]=2;dp[3]=3;dp[4]=1;
int[] dp = new int[n+1];
for(int i=0;i<=n;i++){
dp[i]=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];
}
}