一、爬楼梯(进阶)
之前的爬楼梯最多能爬两个台阶,如果最多能爬m个台阶,那就相当于是m个物品,每个物品可以重复取用,和上一题基本是同样的题了
五部曲
- dp数组,
dp[i],爬到i个台阶,有多少种方法 - 递推公式,
dp[i] += dp[i - j] - dp初始化,
dp[0] = 1 - 遍历顺序,相当于背包里求排列问题,将目标n外循环,爬台阶数m内层循环,从前往后遍历
- 举例推导
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let inputArr;//存放输入的数据
rl.on('line', function(line){
//line是输入的每一行,为字符串格式
inputArr = line.split(' ');//将输入流保存到inputArr中(注意为字符串数组)
}).on('close', function(){
console.log(fun(...inputArr.map(item => Number(item))))//调用函数并输出
})
function fun(n, m) {
let dp = new Array(n + 1).fill(0)
dp[0] = 1
for(let i = 0; i <= n;i++) {
for(let j = 1; j <= m;j++) {
if(i >= j) {
dp[i] += dp[i - j]
}
}
}
return dp[n]
}
二、零钱兑换
五部曲
dp[i],凑成总金额i所需的最少个数- 递推公式,
dp[i] = Math.min(dp[i], dp[j-coins[j]] + 1) - 初始化,
dp[0] = 0,其他初始化为Infinity - 遍历顺序,内层和外层遍历谁都行,都为正序遍历
- 举例
/**
* @param {number[]} coins
* @param {number} amount
* @return {number}
*/
var coinChange = function(coins, amount) {
let dp = new Array(amount + 1).fill(Infinity)
dp[0] = 0
for(let i = 0; i <= amount; i++) {
for(let j = 0; j < coins.length; j++) {
if(i >= coins[j]) {
dp[i] = Math.min(dp[i], dp[i - coins[j]] + 1)
}
}
}
if (dp[amount] === Infinity) {
return -1
}
return dp[amount]
};
三、完全平方数
完全平方数就是物品,凑成正整数n就是背包,解决凑成这个背包最少得物品
五部曲
dp[j], 和为j的完全平方数的最少数量- 递推公式,
dp[j] = Math.min(dp[j], dp[j - i * i] + 1) - dp初始化,
dp[0] = 0,其他初始化为最大值 - 遍历顺序,如果求组合,外层物品,内层背包,求排列,外层背包,内层物品,该题,都可以
- 举例
/**
* @param {number} n
* @return {number}
*/
var numSquares = function(n) {
let dp = new Array(n+1).fill(Infinity)
dp[0] = 0
for(let i = 1; i * i <= n;i++) {
for(let j = i * i; j <= n;j++) {
dp[j] = Math.min(dp[j], dp[j - i * i] + 1)
}
}
return dp[n]
};