代码随想录算法训练营第四十五天|卡码网57 爬楼梯(进阶版)、LeetCode322 零钱兑换、LeetCode279 完全平方数

本文介绍了如何运用动态规划解决卡码网爬楼梯问题(递推公式涉及dp[j]和i),零钱兑换中找到最小硬币数(背包问题),以及计算完全平方数的最小平方和个数(组合问题)。着重强调了dp数组的理解、问题类型对递推公示的影响以及遍历顺序的重要性。
摘要由CSDN通过智能技术生成

卡码网57.爬楼梯

思路:爬上n阶楼梯,每次最多可以上m个台阶 (1<=m<n)。确定dp数组及其下标的含义,dp[j]表示爬上j阶楼梯的方法数。递推公式dp[j] +=dp[j-i]; (1<=i<=m)。初始化dp数组,dp[0]=1,如果初始化dp[0]=0,后续dp的值都为0。遍历顺序,由于物品可以重复使用,因此遍历背包时正序。由于1阶+2阶与2阶+1阶是两种不同的方法,因此是排列问题,先遍历背包后遍历物品。打印dp数组,可以用于debug。

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

int method(int m,int n)
{
    //定义dp数组及其下标含义 dp[j]表示爬到j层楼的楼顶需要的方法数
    //递推公式 dp[j] += dp[j-i], 1<=i<=m。
    //初始化 dp[0]=1。到达0阶的方法数
    //遍历顺序 1阶+2阶 与 2阶+1阶 是两种不同的方法,因此这道题为排列问题
    //循环顺序为先背包后物品
    //打印dp数组,可以用于debug
    vector<int> dp(n+1,0);
    dp[0] =1;
    for(int j = 1;j<=n;j++)
    {
        for(int i = 1;i<=m;i++)
        {
            if(j>=i)
            {
                dp[j]+=dp[j-i];
            }
        }
    }
    return dp[n];
}

int main()
{   
    int m;
    int n ;
    cin >>n;
    cin>>m;
    cout<< method(m,n);
    
    system("pause");
    return 0;
}

322.零钱兑换

思路:求可以凑成总金额的最小硬币个数,确定dp数组及其下标的含义,dp[j]表示凑成j金额的最小硬币数。递推公式 dp[j] = min( dp[j-coins[i]]+1, dp[j]).初始化dp数组,初始化dp数组为INT_MAX,因为如果能凑成金额j,dp数组值会被替换,如果不能凑成仍保持为INT_MAX. dp[0]=0;凑成0金额最小用0个硬币。遍历顺序,因为硬币可以重复使用,背包正序遍历,以为这道题求最小硬币个数因此,先遍历背包还是物品无所谓。打印dp数组,可以用于debug。

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        //coins面额从大到小往背包里放,贪心
        //确定dp数组及其下标的含义,dp[j]代表 容量为j的背包可以放的最小个数
        //递推公式 dp[j] = min(dp[j-coins[i]+1,dp[j]]);
        //初始化dp数组 dp[0] = 0;
        //确定递归顺序,可以重复放,从前往后循环
        //这道题排列和组合都可以解决,因此先遍历背包还是物品都可以
        //打印dp数组,可以用于debug
        vector<int> dp(amount+1,INT_MAX);
        dp[0] =0;
        for(int j = 1;j<=amount;j++)
        {
            for(int i = 0;i<coins.size();i++)
            {
                if(j>=coins[i]&&dp[j-coins[i]]!=INT_MAX)
                {
                    dp[j] = min(dp[j-coins[i]]+1,dp[j]);
                }
            }
        }
        
        return (dp[amount]==INT_MAX)?-1:dp[amount];

    }
};

279.完全平方数

思路:给定一个整数n,返回和为n的最小平方和个数。确定dp数组及其下标含义,dp[j]表示凑满j的最小平方和个数。递推公式dp[j] = min(dp[j-i*i]+1,dp[j])。初始化dp为INT_MAX,dp[0]为0。遍历顺序,因为平方和可以重复利用,遍历背包正序,这道题考虑组合还是排列不会影响结果,因此先遍历背包还是物品都可以。打印dp数组,可以用于debug。

class Solution {
public:
    int numSquares(int n) {
        //确定dp数组及其下标的含义 dp[j]为 装满背包容量为j的最小数量
        //递推公式  dp[j] = min(dp[j-i^2]+1,dp[j]);
        //初始化dp数组 dp[0]=0;
        //遍历顺序 物品可以重复,因此遍历背包是正序
        //打印dp数组,可以用于debug
        vector<int> dp(n+1,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-i*i]+1,dp[j]);
            }
        }
        return dp[n];
    }
};

收获

熟练使用dp数组,理解dp数组的含义,以及问题对递推公示的影响,物品是否重复判断问题是01背包问题还是完全背包问题,遍历背包是倒序还是正序,判断问题是组合还是排列,组合问题先遍历物品,排列问题先遍历背包,如果组合和排列不对结果产生影响,先遍历哪个都可以。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值