一、爬楼梯
题目一:57. 爬楼梯
57. 爬楼梯(第八期模拟笔试)
题目描述
假设你正在爬楼梯。需要 n 阶你才能到达楼顶。
每次你可以爬至多m (1 <= m < n)个台阶。你有多少种不同的方法可以爬到楼顶呢?
注意:给定 n 是一个正整数。
输入描述
输入共一行,包含两个正整数,分别表示n, m
输出描述
输出一个整数,表示爬到楼顶的方法数。
到达第n个台阶的方法数量是到达前面某些台阶的方法数量的总和,具体来说,就是到达第n-1, n-2, ..., n-m个台阶的方法数量的总和,因为每次可以爬1到m个台阶。
定义一个数组
dp
,其中dp[i]
表示到达第i个台阶的方法数。初始化
dp[0] = 1
,因为到达起点(不爬任何台阶)只有一种方法。然后,对于每一个台阶i(从1到n),计算到达这个台阶的方法数,即
dp[i] = dp[i-1] + dp[i-2] + ... + dp[i-m]
,其中i-m > 0
。对于那些
i < m
的台阶,只能从比i小的台阶爬上来,所以在这种情况下,dp[i]
应该是dp[i-1] + dp[i-2] + ... + dp[0]
。
#include <iostream>
#include <vector>
using namespace std;int climbStairs(int n, int m) {vector<long long> dp(n + 1, 0); dp[0] = 1; for (int i = 1; i <= n; ++i) {for (int j = 1; j <= m && i - j >= 0; ++j) {dp[i] += dp[i - j];}}return dp[n];
}int main() {int n, m;cin >> n >> m;cout << climbStairs(n, m) << endl;return 0;
}
二、零钱兑换
题目一:322. 零钱兑换
322. 零钱兑换
给你一个整数数组 coins
,表示不同面额的硬币;以及一个整数 amount
,表示总金额。
计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1
。
你可以认为每种硬币的数量是无限的。
dp[i]
代表组成金额i
所需的最少硬币数。初始化
dp[0] = 0
,因为金额为0时不需要任何硬币。对于所有其他的
i
,可以初始化为一个很大的数,比如amount + 1
,这个值代表无效解,因为组成金额i
最多使用的硬币数不会超过amount
。对于每个金额
i
从1
到amount
,遍历所有的硬币面额,更新dp[i]
为:
/** @lc app=leetcode.cn id=322 lang=cpp** [322] 零钱兑换*/// @lc code=start
class Solution {
public:int coinChange(vector<int>& coins, int amount) {vector<int> dp(amount + 1, amount + 1);dp[0] = 0;for (int i = 1; i <= amount; i++) {for (int coin : coins) {if (i - coin >= 0) {dp[i] = min(dp[i], dp[i - coin] + 1);}}}return dp[amount] > amount ? -1 : dp[amount];}
};
// @lc code=end
三、完全平方数
题目一:279. 完全平方数
279. 完全平方数
给你一个整数 n
,返回 和为 n
的完全平方数的最少数量 。
完全平方数 是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,1
、4
、9
和 16
都是完全平方数,而 3
和 11
不是。
初始时,
dp[0] = 0
,因为组成数0不需要任何完全平方数。动态规划的状态转移方程为:
/** @lc app=leetcode.cn id=279 lang=cpp** [279] 完全平方数*/// @lc code=start
class Solution {
public:int numSquares(int n) {vector<int> dp(n + 1, INT_MAX); dp[0] = 0; for (int i = 1; i <= n; ++i) {for (int j = 1; j*j <= i; ++j) {dp[i] = min(dp[i], dp[i - j*j] + 1);}}return dp[n];}
};
// @lc code=end