算法学习 | day39/60 爬楼梯/零钱兑换/完全平方数

一、题目打卡

        1.1 爬楼梯

        题目链接:57. 爬楼梯(第八期模拟笔试)

#include<iostream>
#include<vector>
using namespace std;


void solve(int &n, int &m){
    vector<int> dp(n+1,0);
    dp[0] = 1;
    
    for(int i = 0 ; i <= n ; i++){
        for(int j = 1 ; j <= m;j++){
            if(i >= j) dp[i] = dp[i] + dp[i - j];
        }
    }
    cout << dp[n];
}


int main(){
    int m, n;
    while(cin >> n >> m){
        solve(n, m);
    }
    return 0;
}

        这个递推的一个思想就是在最终目标点前面的m个步长以内,可以一步到达,所以方法累加就相当于是这个m个步长中所有的方法的总和,或者是思考为背包问题,因为每次走的步数都是从 1 开始到 m 的,因而就变成了一个完全背包问题。

        1.2 零钱兑换

        题目链接:. - 力扣(LeetCode)

// class Solution {
// public:
//     static bool cmp(int &a, int &b){
//         return a > b;
//     }
//     // vector<double> path;
//     int size = 0;
//     double sum = 0.0;
//     int minSize = INT_MAX;
//     // bool backtrack(vector<int>& coins, int& amount, int startInd){
//     //     if(sum == amount) return true;
//     //     if(sum > amount) return false;

//     //     for(int i = startInd; i < coins.size();i++){
//     //         path.push_back(coins[i]);
//     //         sum += coins[i];
//     //         if(backtrack(coins, amount, 0)) return true;
//     //         path.pop_back();
//     //         sum -= coins[i];
//     //     }
//     //     return false;
//     // }
//     void backtrack(vector<int>& coins, int& amount, int startInd){
//         if(sum == amount){
//             minSize = min(minSize, size);
//             return;
//         }
//         if(sum > amount) return;

//         for(int i = startInd; i < coins.size();i++){
//             size++;
//             sum += coins[i];
//             backtrack(coins, amount, 0);
//             size--;
//             sum -= coins[i];
//         }
//     }
//     int coinChange(vector<int>& coins, int amount) {
//         sort(coins.begin(),coins.end(),cmp);
//         backtrack(coins, amount, 0);
//         if(minSize != INT_MAX) return minSize;
//         // if(backtrack(coins, amount, 0)){
//         // for(auto &it : path){
//         //     cout << it << " ";
//         // }        
//         //     return path.size();
//         // }
//         return -1;
//     }
// };

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        vector<int> dp(amount + 1,INT_MAX); // 从 0 到 i 任意选择,组合成 amount 的最小硬币数
        dp[0] = 0;
        for(int i = 0; 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);
            }
        }
        // cout << dp[amount];
        // if(dp[amount] == amount) return dp[amount];
        // return -1;
        if(dp[amount] == INT_MAX) return -1;
        return dp[amount];
    }
};

        回溯不能用贪心的思想,比如419,408, 186, 83 的那个测试案例,如果回溯用排序以后的贪心方法来计算的话,就会导致83用的过多,具体原因我也说不上来,然后就是把这个问题考虑为一个完全背包的问题,因为每个硬币可以重复使用,不过我在一开始做这个题目的时候,有一点没有想明白,就是这个题目是需要凑满,计算最小的个数,那么凑满这个应该怎么表示呢?虽然最后写出来了,但是感觉对这一点我还理解的不是很透彻,我感觉是因为判断条件的保证,这样就相当于从小开始递推,只要是赋值的位置,就一定保证是最小的,到最后就一定可以凑的满。

        另一个题目需要注意的点是,这个是求的是元素的个数,因而和组合的顺序是没有关系的,因而和遍历背包或者遍历物品的顺序是无关的。

        1.3 完全平方数

        题目链接:. - 力扣(LeetCode)

class Solution {
public:
    int numSquares(int n) {
        vector<int> dp(n + 1, INT_MAX);
        dp[0] = 0;
        
        for(int k = 1, i = k * k; i <= n ; k++, i = k*k){
            // cout << i << endl;
            for(int j = i ; j <= n;j++){
                if(dp[j - i] != INT_MAX) dp[j] = min(dp[j], dp[j - i] + 1);
            }
        }
        // for(auto& it: dp){
        //         cout << it << " "; 
            
        // }
        return dp[n];
    }
};

        和上面那个题几乎是一模一样的,不过注意的是,因为这个是从1开始的,所以不存在最终凑不满的情况。

  • 3
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值