• Day 45 | 70. 进阶爬楼梯 & 322. 零钱兑换 & 279.完全平方数


     70. 进阶爬楼梯

    完全背包解题思路: 

    爬楼梯原题目是一次只能爬1/2层台阶,若改为一次可以爬m个台阶,即为完全背包的排列问题

    每次可以跳[1,i],跳到第j阶,共有dp[j]种方法

    递推公式:dp[j]+=dp[j-nums[i]]

    因为是排列问题,因此先遍历容量(跳1/2层台阶),再遍历背包(跳到了多少层台阶)。容量从前往后计算。

    1. public int combinationSum4(int[] nums, int target) {
    2. int[] dp=new int[target+1];
    3. dp[0]=1;
    4. for(int j=0;j<=target;j++){
    5. for(int i=0;i
    6. if(j-nums[i]>=0){
    7. dp[j]+=dp[j-nums[i]];
    8. }
    9. }
    10. }
    11. return dp[target];
    12. }

    322. 零钱兑换 

    完全背包解题思路:

            硬币无限个,凑成总金额(装满背包):完全背包问题

            本题求的是最少硬币个数,可转换为[0,i[个硬币,凑成金额j,所需钱币最少为dp[j]

    每次遍历时有两种选择:

    ①取:dp[j]=dp[j-nums[i]+1  (凑成金额为j-nums[i[所需的最少硬币再加1即为凑成j的最少硬币数)

    ②不取,dp[j]=dp[j]

    因为求的是最少硬币数,每次对这两个数取小即可。

    因此,状态转移方程为:dp[j]=Math.min(dp[j],dp[j-nums[i]]+1);

    数组的初始化

            所有dp[j]都先定义为为最大值。dp[0]=0,当金额为0时要0个硬币。

    数组的遍历顺序

            完全背包问题,本题是要求最少硬币数量,硬币是组合数还是排列数都无所谓!所以两个for循环先后顺序怎样都可以。但是遍历容量要从前向后遍历,满足一个硬币可放多次的条件。

    1. int max=Integer.MAX_VALUE;
    2. int[] dp=new int[amount+1];
    3. for(int j=0;j<=amount;j++){
    4. dp[j]=max;
    5. }
    6. dp[0]=0;
    7. for(int i=0;i
    8. for(int j=coins[i];j<=amount;j++){
    9. //当dp[j-coins]不为max时比较才有意义
    10. if(dp[j-coins[i]]!=max){
    11. dp[j]=Math.min(dp[j],dp[j-coins[i]]+1);}
    12. }
    13. }
    14. return dp[amount]==max?-1:dp[amount];

    279. 完全平方数

    完全背包解题思路:

            每个物品为i*i(平方数),物品有无限个,凑成和为j,最小有dp[j]个完全平方数。

    ①确定dp数组以及下标含义

            dp[j]:每个物品大小为i*i,装满容量j的背包,最少个数为dp[j]个。

    ②确定递推公式

            遇上题相同,求的是最小个数。

    取的时候为装满容量j-i*i的最少个数+1(当前这个数);不取即为dp[j]

                                            dp[j]=Math.min(dp[j],dp[j]-i*i]+1); 

    ③dp数组如何初始化

          所有dp[j]都先定义为为最大值。dp[0]=0,

    ④确定遍历顺序

            与上一题相同。

            本题是要求最少平方数的个数,是组合数还是排列数都无所谓!所以两个for循环先后顺序怎样都可以。但是遍历容量要从前向后遍历,满足一个数可放多次的条件。

    ⑤举例推导dp数组

       n=5 :

    1. public int numSquares(int n) {
    2. int[] dp = new int[n + 1];
    3. int max = Integer.MAX_VALUE;
    4. for (int j = 0; j <= n; j++) {
    5. dp[j] = max;
    6. }
    7. dp[0] = 0;
    8. for (int i = 1; i * i <= n; i++) {
    9. for (int j = i * i; j <= n; j++) {
    10. if (dp[j - i * i] != max) {
    11. dp[j] = Math.min(dp[j], dp[j - i * i] + 1);
    12. }
    13. }
    14. }
    15. return dp[n];
    16. }

  • 相关阅读:
    python列表合并,去重
    数据结构(C语言)——单链表
    CSS 定位布局
    Web系统常见安全漏洞介绍及解决方案-XSS攻击
    MySQL 慢查询日志 使用方法浅析 日志定位与优化技巧
    云原生可观测框架 OpenTelemetry 基础知识(架构/分布式追踪/指标/日志/采样/收集器)
    C语言生成随机数、C++11按分布生成随机数学习
    什么是数据仓库的mapping
    Linux命令(94)之tail
    Linux系统编程·进程概念引入
  • 原文地址:https://blog.csdn.net/m0_56579820/article/details/127700979