LeetCode70. 爬楼梯 (进阶)
爬楼梯问题将每次最多爬两步改成爬m步,那么就变成一个完全背包问题,1阶,2阶...m阶为商品,楼梯总数为背包容量,问有几种方法装满背包,此为求排列问题,因此先遍历背包容量,再遍历物品,代码如下:时间复杂度O(m*n),空间复杂度O(n).
#include <iostream>
#include <vector>
using namespace std;
int main() {
int n, m;
while (cin >> n >> m) {
vector<int> dp(n + 1, 0);
dp[0] = 1;
for (int i = 1; i <= n; i++) { // 遍历背包
for (int j = 1; j <= m; j++) { // 遍历物品
if (i - j >= 0) dp[i] += dp[i - j];
}
}
cout << dp[n] << endl;
}
}
LeetCode322. 零钱兑换
动规五部曲:
dp[i]数组含义:容量为i的背包装满最少有几件物品;
递推公式:dp[i] = min(dp[i],dp[i-coins[j]]+1);
初始化:dp[0]=0,非零下标初始为INT_MAX;
遍历顺序:本题是一个完全背包问题,因此从前往后遍历,至于先遍历背包还是先遍历物品,都可以,因此是求得最少的硬币数,与排列顺序无关,无所谓求排列问题还是组合问题。由于初始化为INT_MAX,并且后序涉及到+1的操作,需要加一个判别是否为初始值的逻辑,否则int类型会溢出。
打印dp数组;
先遍历背包代码如下:时间复杂度O(m*n);空间复杂度O(n)
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount+1,INT_MAX);
dp[0] = 0;
for(int i=0;i<=amount;i++){
for(int j=0;j<coins.size();j++){
if(i-coins[j]>=0 && dp[i-coins[j]]!=INT_MAX){
dp[i] = min(dp[i],dp[i-coins[j]]+1);
}
}
}
if(dp[amount] == INT_MAX) return -1;
return dp[amount];
}
};
LeetCode279.完全平方数
本题和上一题思路思路基本一样,上一题是先遍历背包容量,那么本题就先遍历物品,由于不会出现没有解的情况,所以处理节点前面的dp数组的值都会被更新,不需要加入判断是否为初始值的逻辑,代码如下:时间复杂度O(m*n);空间复杂度O(n)。
class Solution {
public:
int numSquares(int n) {
//背包容量是n,物品数量也是sqrt(n),价值是平方
vector<int> dp(n+1,INT_MAX);
dp[0] = 0;
for(int i=1;pow(i,2)<=n;i++){
for(int j=pow(i,2);j<=n;j++){
dp[j] = min(dp[j],dp[j-pow(i,2)]+1);
}
}
return dp[n];
}
};