DAY48:动态规划(十一)爬楼梯(进阶版)+零钱兑换(理解DP数组“装满“含义)

news2024/10/7 4:25:34

文章目录

    • 70.爬楼梯(改版题目)
      • 思路
        • 遍历顺序
      • 完整版
      • 总结+面试情况
    • 322.零钱兑换(DP数组含义的进一步理解)
      • 思路
      • DP数组含义
      • 递推公式
      • 遍历顺序
      • 初始化
      • 最开始的写法
        • debug逻辑错误:背包不一定装满
      • 修改完整版
      • 递归逻辑分析
      • 背包是否”装满“的判断
      • 总结:装满背包最大/最小物品个数类

70.爬楼梯(改版题目)

  • 本题是装满背包的排列数问题

  • 看是组合还是排列问题,只要看取同样两个物品,顺序不同的时候,是不是同样的方案就行了。

  • 完全背包排列数问题,注意数组下标越界所以要加上限制条件

力扣原题:(斐波那契数列)

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 12 个台阶。你有多少种不同的方法可以爬到楼顶呢?

改版:

假设你正在爬楼梯。需要 n 阶你才能到达楼顶。

每次你可以爬 m (0<m<n) 个台阶。你有多少种不同的方法可以爬到楼顶呢?

思路

每次可以爬m个台阶,意味着每一步都可以在1–m之间任意选择,因此可以转化为一个背包问题,每一步的m就是物品,n就是背包的容量,且物品可以重复选取(例如跳了1阶,还可以再跳1阶),因此是一个完全背包问题。

可以转化为,每一次取物品都在{1,2,……m}之间进行取值可以重复取同一个物品最后需要填满容量为n的背包,共有多少种方法?

遍历顺序

本题重要的是确认到底是组合数还是排列数。因为每次取物品可以在{1,2,……m}之间进行取值,而且取"1""2"和取“2""1"是不一样的!第一步先走1步还是先走2步,是两种不一样的方案!

看是组合还是排列,只要看取同样两个物品,顺序不同的时候,是不是同样的方案就行了。

因此,这是完全背包排列数问题,背包在外,物品在内。

完整版

  • 也属于填满背包的方法问题,且为组合数,物品在外,背包在内
  • 注意公式一直都是背包容量在左边!不管背包容量是i还是j
class Solution {
public:
    int climbStairs(int n,int 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){
                     dp[i]+=dp[i-j];//注意公式一直都是背包容量在左边!不管背包容量是i还是j!
                }
               
            }
        }
        return dp[n];
    }
};

总结+面试情况

本题看起来是一道简单题目,稍稍进阶一下其实就是一个完全背包

面试可能的情况是,先给候选人出一个爬楼梯原题,再出本题,看其表现,如果顺利写出来,进而在要求每次可以爬[1 - m](这里的意思是每次可以爬的台阶是{1,2……m},要注意确认意图)个台阶应该怎么写。

顺便再考察一下两个for循环的嵌套顺序为什么target放外面,nums放里面

这就能考察对背包问题本质的掌握程度,候选人是不是刷题背公式,一眼就看出来了。

322.零钱兑换(DP数组含义的进一步理解)

  • 本题与 474.一和零 很像,属于装满背包的最小物品个数,一和零 是装满背包最大物品个数

给你一个整数数组 coins ,表示不同面额的硬币;以及一个整数 amount ,表示总金额。

计算并返回可以凑成总金额所需的 最少的硬币个数 。如果没有任何一种硬币组合能组成总金额,返回 -1 。

你可以认为每种硬币的数量是无限的。

示例 1:

输入:coins = [1, 2, 5], amount = 11
输出:3 
解释:11 = 5 + 5 + 1

示例 2:

输入:coins = [2], amount = 3
输出:-1

示例 3:

输入:coins = [1], amount = 0
输出:0

提示:

  • 1 <= coins.length <= 12
  • 1 <= coins[i] <= 231 - 1
  • 0 <= amount <= 104

思路

首先本题也属于给定目标(背包容量),要求填满背包的问题。

题目描述中说每种硬币数量无限,因此是完全背包问题。

本题和 零钱兑换Ⅱ 的区别就是,零钱兑换Ⅱ 是要求返回凑成amount的组合数,而本题是返回凑成amount的最少硬币的数量

装满背包的最少物品数量的递推逻辑,和 474.一和零 类似:DAY46:动态规划(八)01背包应用2:一和零(二维容量01背包)_大磕学家ZYX的博客-CSDN博客

DP数组含义

dp[j]含义是容量为j的背包,填满背包的最少硬币数目是dp[j]

递推公式

和474.一和零 递推公式类似,求装满背包物品个数,也是一个求历史最小值的过程

dp[j]=min(dp[j],dp[j-coins[i]]+1);//这里的+1,是增加了一个物品的意思,因为求的是个数,就把value值改为了1!

遍历顺序

本题求物品最小个数,那么物品有顺序和没有顺序都可以,都不影响物品的最小个数

所以本题并不强调集合是组合还是排列。

如果求组合数就是外层for循环遍历物品,内层for遍历背包

如果求排列数就是外层for遍历背包,内层for循环遍历物品

初始化

最小硬币个数,为了min值能够进行替代,最开始初始化需要都初始化为INT_MAX

最开始的写法

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        //先定义为INT_MAX
        vector<int>dp(amount+1,INT_MAX-1);
        dp[0]=0;
        //物品在外,实际上都可以
        for(int i=0;i<coins.size();i++){
            for(int j=1;j<=amount;j++){
                if(j>=coins[i]){
                    dp[j]=min(dp[j],dp[j-coins[i]]+1);
                }
            }
        }
		return dp[amount];
    }
};

debug逻辑错误:背包不一定装满

在这里插入图片描述

这个问题中, 因为dp数组的含义是填满容量为j的背包,最少硬币个数是dp[j],因此dp[j]如果有数值,就一定是填满了的如果没有填满,值就是初始化的数值

修改完整版

class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        //先定义为INT_MAX,DP数组含义是填满j背包,最少需要dp[j]个硬币
        vector<int>dp(amount+1,INT_MAX-1);
        //初始化很重要,最开始只有j=coins[i]的时候才会有继续的数值
        dp[0]=0;
        //物品在外,实际上都可以
        for(int i=0;i<coins.size();i++){
            for(int j=coins[i];j<=amount;j++){
                //如果dp[j-coins[i]]是初始值,说明没有填满,凑不成这个金额j
                if(dp[j-coins[i]]==INT_MAX) continue;
                //能填满再更新数值
                dp[j]=min(dp[j],dp[j-coins[i]]+1);
            }
        }
        if(dp[amount]==INT_MAX)  return -1;
		return dp[amount];
    }
};

颠倒遍历顺序的版本

  • 颠倒for的顺序,再修改if里面的边界条件即可
// 版本二
class Solution {
public:
    int coinChange(vector<int>& coins, int amount) {
        vector<int> dp(amount + 1, INT_MAX);
        dp[0] = 0;
        for (int i = 1; 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 - coins[j]] + 1, dp[i]);
                }
            }
        }
        if (dp[amount] == INT_MAX) return -1;
        return dp[amount];
    }
};

递归逻辑分析

dp[j]表示凑出金额j所需的最少硬币数量,初始化为 INT_MAX,表示“不可能”。当我们选择硬币coins[i]时,有两种可能:

  1. 不选这个硬币,那么dp[j]保持原来的值,即“前一步的最优解”。
  2. 选这个硬币,那么dp[j]应该更新为 dp[j-coins[i]] + 1,即“选这个硬币后还需要凑出金额i-coins[j],再加上这一个硬币”。

注意到这里的dp[j-coins[i]] + 1如果dp[j-coins[i]]是初始值INT_MAX,表示“凑出金额j-coins[i]是不可能的”,那么即使我们选择了硬币coins[i],仍然不能凑出金额j。因此在这种情况下我们应该跳过,保持dp[j]为原来的值

另一方面,如果dp[j-coins[i]] + 1不是初始值,即"凑出金额j-coins[i]是可能的",也就是说这种情况下背包已经装满了。那么我们可以选择硬币coins[i],并更新dp[j]

背包是否”装满“的判断

在背包问题中,DP数组的含义和它的初始化是密切相关的。在 零钱兑换 问题中,我们是希望找到凑出目标金额所需的最小硬币数,所以dp数组的含义是“使用最小数量的物品装满背包”,这也就决定了我们需要将dp数组初始化为无穷大(INT_MAX)。在这种情况下,dp[j]值更新意味着我们找到了一种新的方式来填满金额j,也就是说背包是填满的

然而,对于其它的背包问题,比如纯完全背包问题,dp[j]的含义是“背包容量为j时的最大价值”,初始化为0,表示开始时背包是空的,没有价值。对于每一个物品,我们可以选择拿或者不拿,如果拿的话,就是dp[j - weight[i]] + value[i],如果不拿,就是dp[j]。我们取两者中的最大值,这样可以保证我们总是得到最大价值。在这种情况下,背包并不一定是填满的,因为我们的目标是使背包的总价值最大,而不是一定要填满背包。

总结:装满背包最大/最小物品个数类

  • 递推公式:因为求的是个数,所以,把完全背包的递推公式,物品value值改为1即可。递推公式最后+1,是增加了一个物品的意思。
  • 遍历顺序:求物品个数的类型题,因为物品不管是排列方案数和组合方案数,都不影响物品的最后个数,因此物品个数类型题,遍历顺序都可以并不需要限制是组合方案数
  • 初始化:如果求的是最小物品个数,还需要注意要全部初始化成INT_MAX
  • 474.一和零 说的是该子集最多m个0,n个1,所以默认背包是填满的如果要求填不满返回-1,还要考虑dp数组是不是为初始值的问题。这类问题,DP数组只要不是初始值,都是默认填满了的,如果DP数组dp[amount]是初始值,说明没有填满!(从DP数组的含义来分析)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/768493.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

极值理论 EVT、POT超阈值、GARCH 模型分析股票指数VaR、条件CVaR:多元化投资组合预测风险测度分析...

全文链接&#xff1a;http://tecdat.cn/?p24182 本文用 R 编程语言极值理论 (EVT) 以确定 10 只股票指数的风险价值&#xff08;和条件 VaR&#xff09;&#xff08;点击文末“阅读原文”获取完整代码数据&#xff09;。 使用 Anderson-Darling 检验对 10 只股票的组合数据进行…

EFCore—context在其他程序集时如何进行数据迁移

场景 解决方案&#xff1a; 代码示例&#xff1a; 场景 一般来说&#xff0c;如果efcore进行数据迁移的步骤如下 安装nuget包创建实体类创建config创建dbcontext 然后执行如下命令就可以成功迁移了 Add-Migration Init Update-Database 一执行&#xff0c;报错 Unable t…

(四)「消息队列」之 RabbitMQ 路由(使用 .NET 客户端)

0、引言 先决条件 本教程假设 RabbitMQ 已安装并且正在 本地主机 的标准端口&#xff08;5672&#xff09;上运行。如果您使用了不同的主机、端口或凭证&#xff0c;则要求调整连接设置。 获取帮助 如果您在阅读本教程时遇到问题&#xff0c;可以通过邮件列表或者 RabbitMQ 社区…

k8s之Pod容器的探针

目录 一、Pod 容器的探针二、探针的探测方式2.1 存活探针的使用2.1.1 exec方式2.1.2 httpGet方式2.1.3 tcpSocket方式 2.2 就绪探针的使用2.3 启动探针的使用2.4 7.Pod 容器的启动和退出动作 三、总结 一、Pod 容器的探针 探针是由 kubelet 对容器执行的定期诊断&#xff08;p…

M1安装ParallelsDesktop-18 重启镜像后无网络

M1安装ParallelsDesktop-18 重启镜像后无网络 重新关联镜像 sudo -b /Applications/Parallels\ Desktop.app/Contents/MacOS/prl_client_app

手机定屏死机问题操作指南

和你一起终身学习&#xff0c;这里是程序员Android 经典好文推荐&#xff0c;通过阅读本文&#xff0c;您将收获以下知识点: 一、定屏死机问题抓取 Log 要求二、 复现定屏死机问题后做什么三、检查adb是否可连的方法四、连接adb 抓取以下Log五、如果adb不可连&#xff0c;执行下…

一、数制及其转换

目录 常用进制介绍 十进制 二进制 八进制 十六进制 进制转换 二进制转十进制 十进制转二进制 二进制转十六进制 十六进制转二进制 二进制转八进制 八进制转二进制 十六进制转八进制 八进制转十六进制 常用进制介绍 十进制 介绍&#xff1a;十进制是日常生活中最…

基于linux下的高并发服务器开发(第二章)- 2.9 waitpid 函数

#include <sys/types.h> #include <sys/wait.h>pid_t waitpid(pid_t pid, int *wstatus, int options); 功能&#xff1a;回收指定进程号的子进程&#xff0c;可以设置是否阻塞。 参数&#xff1a; - pid: pid > 0…

Versal ACAP在线升级之Boot Image格式

1、简介 Xilinx FPGA、SOC器件和自适应计算加速平台&#xff08;ACAPs&#xff09;通常由多个硬件和软件二进制文件组成&#xff0c;用于启动这些设备后按照预期设计进行工作。这些二进制文件可以包括FPGA比特流、固件镜像、bootloader引导程序、操作系统和用户选择的应…

打造有效的产品帮助中心的关键步骤

在当今竞争激烈的市场中&#xff0c;为产品提供优质的客户支持是至关重要的。而一个有效的产品帮助中心可以成为解决客户问题和提供相关信息的中心。本文将介绍打造一个有效的产品帮助中心的关键步骤&#xff0c;帮助你提升客户体验并增强产品的用户满意度。 1. 选择合适的管理…

记一次ruoyi中使用Quartz实现定时任务

一、首先了解一下Quartz Quartz是OpenSymphony开源组织在Job scheduling领域又一个开源项目&#xff0c;它可以与J2EE与J2SE应用程序相结合也可以单独使用。Quartz可以用来创建简单或为运行十个&#xff0c;百个&#xff0c;甚至是好几万个Jobs这样复杂的程序。Jobs可以做成标…

13matlab数据分析多项式的求值(matlab程序)

1.简述 统计分析常用函数 求最大值 max 和 sum 积 prod 平均值&#xff1a;mean 累加和&#xff1a;cumsum 标准差&#xff1a;std 方差&#xff1a;var 相关系数&#xff1a;corrcoef 排序&#xff1a;sort 四则运算 1.多项式的加减运算就是所对应的系数向量的加减运算&#…

ToT: 利用大语言模型解决需要深思熟虑的问题(下)

ToT 摘要介绍利用大语言模型进行有意识的问题解决1. 思维分解2. 思维产生 G(p,s,k)3. 状态评估V(p,S)4. 搜索算法 实验24游戏1). 任务设置2). 基准3). ToT设置4).结果5). 错误分析 创意写作1). 任务设置2).基准3).ToT设置4).结果 交叉词 相关工作规划和决策自我反省程序引导的L…

常见问题-wp

指定顺序展示富集分析的term 调整热图的label角度 h1ggheatmap(dat[cg1,],cluster_rows T, #是否对行聚类cluster_cols T, #是否对列聚类tree_height_rows 0.28, #行聚类树高度tree_height_cols 0.1, #列聚类树高度annotation_cols group_list, #为列添加分组annotation_c…

软件检测报告对软件产品起的作用和编写原则分析

软件检测报告是一项对软件进行全面测试和评估的结果总结&#xff0c;通过对软件的功能、性能、安全性等方面的测试&#xff0c;以及通过分析软件的可靠性和稳定性&#xff0c;来评估软件的质量和合规性。 一、软件检测报告对软件产品起到的作用 1、提供一个全面的评估和分析软…

认识主被动无人机遥感数据、预处理无人机遥感数据、定量估算农林植被关键性状、期刊论文插图精细制作与Appdesigner应用开发

目录 第一章、认识主被动无人机遥感数据 第二章、预处理无人机遥感数据 第三章、定量估算农林植被关键性状 第四章、期刊论文插图精细制作与Appdesigner应用开发 更多推荐 遥感技术作为一种空间大数据手段&#xff0c;能够从多时、多维、多地等角度&#xff0c;获取大量的…

NAT 地址转换路由器配置命令(华为路由器)

#AR1路由器配置 # acl 2000 rule permit source any # interface GigabitEthernet0/0/1 nat outbound 2000 ip address 1.1.1.1 24 # interface GigabitEthernet0/0/0 ip address 172.16.1.1 255.255.255.0 # ip route-static 0.0.0.0 0.0.0.0 1.1.1.2 ip route-static …

工业平板电脑具备IP65防护等级,防尘、防水、防震

随着科技的快速发展&#xff0c;工业平板电脑已经成为了我们日常生活中不可或缺的一部分。而在不同领域中&#xff0c;各行各业的专业需求也在不断增长。针对工业领域的专业需求&#xff0c;工业平板电脑应运而生。它以出色的外观设计、强大的性能和丰富的功能&#xff0c;为工…

【iOS】对象的本质探索

OC对象的底层结构 问题&#xff1a;一个NSObject对象在内存中是如何布局的&#xff1f;NSObject的内存布局1 通过 lldb命令 窥探NSObject内存布局2 通过 View Memory 窥探NSObject内存布局3 通过 底层函数API 窥探NSObject内存布局总结 通过继承关系进一步了解NSObject1 运行项…

【SwitchyOmega】SwitchyOmega 安装及使用

文章目录 安装教程使用教程 安装教程 SwitchyOmega 谷歌商店下载链接&#xff1a;https://chrome.google.com/webstore/detail/proxy-switchyomega/padekgcemlokbadohgkifijomclgjgif?hlen-US 在谷歌商店搜索 SwitchyOmega&#xff0c; 选择 Proxy SwitchyOmega 点击 Add t…