卡码网 57. 爬楼梯
题目链接:卡码网 57. 爬楼梯
题目描述: 假设你正在爬楼梯。需要 n
阶你才能到达楼顶。 每次你可以爬至多m (1 <= m < n)
个台阶。你有多少种不同的方法可以爬到楼顶呢? 注意:给定n
是一个正整数。
输入描述: 输入共一行,包含两个正整数,分别表示n
m
输出描述: 输出一个整数,表示爬到楼顶的方法数。
思路: 本题可以抽象成完全背包问题:1阶,2阶,… m阶就是物品,楼顶就是背包。
dp[i]
:爬到有i
个台阶的楼顶,有dp[i]
种方法。- 递推公式为:
dp[i] += dp[i - j]
- 初始化:
dp[0]=1
- 遍历顺序:由于本题需要求不同方法数,也就是排列数,因此需要先遍历背包,再遍历物品
代码如下:
#include<iostream>
using namespace std;
int dp[35];
int main()
{
int n , m;
cin >> n >> m;
dp[0] = 1;
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++ )
if(i >= j)
{
dp[i] += dp[i - j];
}
cout << dp[n];
return 0;
}
- 时间复杂度: O ( n m ) O(n m) O(nm)
- 空间复杂度: O ( n ) O(n) O(n)
Leetcode 322. 零钱兑换
题目链接:Leetcode 322. 零钱兑换
题目描述: 给你一个整数数组 coins
,表示不同面额的硬币;以及一个整数 amount
,表示总金额。计算并返回可以凑成总金额所需的最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1
。你可以认为每种硬币的数量是无限的。
思路: 本题也属于完全背包问题。
dp[j]
:凑足总额为j
所需钱币的最少个数为dp[j]
- 递推公式:
dp[j] = min(dp[j - coins[i]] + 1, dp[j])
- 初始化:
dp[0]=0
,其他元素需要初始化一个大于数据范围的数。 - 遍历顺序:本题求钱币最小个数,那么钱币有顺序和没有顺序都可以,都不影响钱币的最小个数。因此两种遍历顺序都可以。
代码如下:
(先遍历物品,再遍历背包)
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount + 5, INT_MAX);
dp[0] = 0;
for (int i = 0; i < coins.size(); i++) // 遍历物品
for (int j = coins[i]; j <= amount; j++) // 遍历背包
if (dp[j - coins[i]] != INT_MAX)
dp[j] = min(dp[j], dp[j - coins[i]] + 1);
if (dp[amount] == INT_MAX)
return -1;
else
return dp[amount];
}
};
(先遍历背包,再遍历物品)
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount + 5, INT_MAX);
dp[0] = 0;
for (int i = 1; i <= amount; i++) // 遍历背包
for (int j = 0; j < coins.size(); j++) // 遍历物品
if (i >= coins[j] && dp[i - coins[j]] != INT_MAX) {
dp[i] = min(dp[i], dp[i - coins[j]] + 1);
}
if (dp[amount] == INT_MAX)
return -1;
else
return dp[amount];
}
};
- 时间复杂度:
O
(
n
×
a
m
o
u
n
t
)
O(n × amount)
O(n×amount),其中
n
为coins
的长度 - 空间复杂度: O ( a m o u n t ) O(amount) O(amount)
Leetcode 279.完全平方数
题目链接:Leetcode 279.完全平方数
题目描述: 给你一个整数 n
,返回和为 n
的完全平方数的最少数量 。完全平方数是一个整数,其值等于另一个整数的平方;换句话说,其值等于一个整数自乘的积。例如,
1
、
4
、
9
1、4、9
1、4、9 和
16
16
16 都是完全平方数,而
3
3
3 和
11
11
11 不是。
思路: 本题也属于完全背包问题。
dp[j]
:和为j
的完全平方数的最少数量为dp[j]
- 递推公式:
dp[j] = min(dp[j - i * i] + 1, dp[j])
dp[0]=0
,其他元素需要初始化一个大于数据范围的数。- 遍历顺序:本题也只是统计最小数量,因此两种遍历顺序都可以
代码如下:
(先遍历物品,再遍历背包)
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n + 5, INT_MAX);
dp[0] = 0;
for (int i = 1; i * i <= n; i++)//遍历物品
for (int j = i * i; j <= n; j++)//遍历背包
dp[j] = min(dp[j], dp[j - i * i] + 1);
return dp[n];
}
};
(先遍历背包,再遍历物品)
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n + 5, INT_MAX);
dp[0] = 0;
for (int i = 0; i <= n; i++)//遍历背包
for (int j = 1; j * j <= i; j++)//遍历物品
dp[i] = min(dp[i], dp[i - j * j] + 1);
return dp[n];
}
};
- 时间复杂度: O ( n × n ) O(n \times \sqrt{n}) O(n×n)
- 空间复杂度: O ( n ) O(n) O(n)
总结: 理解了完全背包问题之后,这三道题还是很简单的,唯一的难点在于将题目抽象成完全背包问题。
最后,如果文章有错误,请在评论区或私信指出,让我们共同进步!