题目一 爬楼梯进阶版
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬 1 或 2 个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
改为:一步一个台阶,两个台阶,三个台阶,.......,直到 m个台阶。问有多少种不同的方法可以爬到楼顶呢?
思路
1个、2个、3个台阶可以重复使用n次,完全背包问题,动态规划四部曲:
-
dp[j]: 爬到n阶的方法数
-
递推公式: dp[j] += dp[j-i], 是爬1个、2个。。。j-1个台阶的方法数相加
-
初始化:dp[0] = 1
-
循环:顺序不同属于不同的方法,是排列问题,要外层循环重量,内层循环物品
var climbStairsm = function(n, m) {
const dp = new Array(n + 1).fill(0);
dp[0] = 1;
for (let j = 1; j <= n; j++) {
for (let i = 1; i <= m; i++) {
if (j >= i) {
dp[j] += dp[j - i];
}
}
}
return dp[n];
};
climbStairsm(4, 2)
题目二 322. 零钱兑换
给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。
你可以认为每种硬币的数量是无限的。
思路
每种硬币数量无限:完全背包问题。物品就是硬币,重量是amount,四步曲分析:
- dp[j]: 凑成amount所需的最少的硬币个数
- 递推公式: dp[j] = min(dp[j], dp[j - coins[i]]
- 初始化:dp[0] = 1
- 循环:最少硬币个数,跟顺序无关, 先遍历物品,再遍历重量
var coinChange = function(coins, amount) {
const dp = new Array(amount + 1).fill(Number.MAX_VALUE);
dp[0] = 0;
const len = coins.length;
for (let i = 0; i < len; i++) {
for (let j = coins[i]; j <= amount; j++) {
dp[j] = Math.min(dp[j], dp[j - coins[i]] + 1);
}
}
if (dp[amount] === Number.MAX_VALUE) {
return -1;
}
return dp[amount];
};
题目三 279. 完全平方数
给你一个整数 n ,返回 和为 n 的完全平方数的最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1、4、9 和 16 都是完全平方数,而 3 和 11 不是。
思路
和上一题基本类似。
- dp[j]: 返回和为i的完全平方式的最少个数
- 递推公式: dp[j] = min(dp[j - i * i] + 1, dp[j]]
- 初始化:dp[0] = 1;
- 循环顺序:无关顺序,先循环物品,后循环重量
var numSquares = function(n) {
const dp = new Array(n + 1).fill(Number.MAX_VALUE);
dp[0] = 0;
for (let i = 1; i <= n; i++) {
const value = i * i;
for (let j = value; j <= n; j++) {
dp[j] = Math.min(dp[j], dp[j - value] + 1)
}
}
return dp[n];
};