【1691. 堆叠长方体的最大高度】

news2024/10/7 5:24:35

来源:力扣(LeetCode)

描述:

  给你 n 个长方体 cuboids ,其中第 i 个长方体的长宽高表示为 cuboids[i] = [widthi, lengthi, heighti]下标从 0 开始)。请你从 cuboids 选出一个 子集 ,并将它们堆叠起来。

  如果 widthi <= widthjlengthi <= lengthj 且 heighti <= heightj ,你就可以将长方体 i 堆叠在长方体 j 上。你可以通过旋转把长方体的长宽高重新排列,以将它放在另一个长方体上。

返回 堆叠长方体 cuboids 可以得到的 最大高度

示例 1:

1

输入:cuboids = [[50,45,20],[95,37,53],[45,23,12]]
输出:190
解释:
第 1 个长方体放在底部,53x37 的一面朝下,高度为 95 。
第 0 个长方体放在中间,45x20 的一面朝下,高度为 50 。
第 2 个长方体放在上面,23x12 的一面朝下,高度为 45 。
总高度是 95 + 50 + 45 = 190

示例 2:

输入:cuboids = [[38,25,45],[76,35,3]]
输出:76
解释:
无法将任何长方体放在另一个上面。
选择第 1 个长方体然后旋转它,使 35x3 的一面朝下,其高度为 76

示例 3:

输入:cuboids = [[7,11,17],[7,17,11],[11,7,17],[11,17,7],[17,7,11],[17,11,7]]
输出:102
解释:
重新排列长方体后,可以看到所有长方体的尺寸都相同。
你可以把 11x7 的一面朝下,这样它们的高度就是 17 。
堆叠长方体的最大高度为 6 * 17 = 102

提示:

  • n == cuboids.length
  • 1 <= n <= 100
  • 1 <= widthi, lengthi, heighti <= 100

方法一:动态规划

思路与算法

  由于题目要求长方体的高度最大,由此很容易想到将每个长方体的最长边做为高度是最优的,但这种堆叠方法是否正确需要进一步思考。假设两个长方体 r1, r2 的长宽高分别为 (w1, l1, h1) (w2, l2, h2) ,且满足 w1 ≤ w2, l1 ≤ l2, h1 ≤ h2,此时长方体 r1 一定可以堆叠在长方体 r2 之上,此时得到的高度为 h1 + h2 。我们将长方体 r1, r2 的长宽高按照从小到大的顺序重新进行排列为 (w1′, l1′, h1′) 与 (w2′, l2′, h2′) ,且满足 w1′ ≤ l1′ ≤ h1′, w1′ ≤ l1′ ≤ h1′ 。此时我们只需要证明 w1′ ≤ w2′, l1′ ≤ l2′, h1′ ≤ h2′,即可满足堆叠条件。证明如下:

  • 根据之前的结论可知道 r1 中的最大值一定小于等于 r2 中的最大值,r1 中的最小值一定小于等于 r2 中的最小值,否则一定不会出现 w1 ≤ w2, l1 ≤ l2, h1 ≤ h2,此时一定可以推出 w1′ ≤ w2′, l1′ ≤ l2′, h1′ ≤ h2′。此时我们假设 l1′ > l2′ ,则此时可以推出 w1′ ≤ w2′ ≤ l2′<l1′ ≤ w1′ ≤ w2′ 。按照之前的推论可知 r1 中一定存在一个元素小于 w2′ ,存在另外一个元素小于 l2′ ,而此时小于等于 w2′,l2′ 的元素只有一个,与上述结论相矛盾,因此我们一定可以得出结论 l1′ ≤ l2′ 。因此 w1′ ≤ w2′,l1′ ≤ l2′, h1′≤h2′ 结论成立。

  当按照长方体的三条边从小到大进行排序后,此时长方体的高度即对应了三条边中的最大值,那么整个长方体的堆叠高度之和一定不会大于每个长方体的最大边之和,因此最优的堆叠方法一定是基于最长边作为高度的。

  我们下一步计算整个堆叠高度,我们可以设 dp[i] 表示以第 i 个长方体 (wi′, li′, hi′) 为最后一个长方体的最大堆叠高度,可以使用动态规划并写出状态转移方程:

1
  我们需要找到找到所有可以放置到 i 长方体之上的长方体 j,长方体 j 需要满足 wj′ ≤ wi′, lj′ ≤ li′, hj′ ≤ hi′ 。如果不存在可以堆叠的长方体,此时 dp[i]=hi′ ,最终最大的堆叠高度即为 max⁡(dp[i]) 。

  如果想要实现上述的动态规划,必须保证当枚举到第 i 长方体时,所有可以堆叠在第 i 个长方体之上的长方体都应该枚举过,因此在动态规划之前,我们应保证所有满足可堆叠在第 i 个长方体之上的长方体排在 iii 之前,可以利用排序来解决这个问题。这里有非常多的排序方法,只要保证枚举关系的拓扑性即可,例如我们可以使用关键字 (wi′, li′, hi′) 排序,无论采用何种排序方法只需满足当 wj′ ≤ wi′, lj′ ≤ li′, hj′ ≤ hi′ 时,一定满足 j ≤ i 即可。

代码:

class Solution {
public:
    int maxHeight(vector<vector<int>>& cuboids) {
        int n = cuboids.size();
        for (auto & v : cuboids) {
            sort(v.begin(), v.end());
        }
        sort(cuboids.begin(), cuboids.end(), [](const vector<int> & a,const vector<int> & b) {
            return a[0] + a[1] + a[2] < b[0] + b[1] + b[2];
        });
        int ans = 0;
        vector<int> dp(n);
        for (int i = 0; i < n; i++) {
            dp[i] = cuboids[i][2];
            for (int j = 0; j < i; j++) {
                if (cuboids[i][0] >= cuboids[j][0] && 
                    cuboids[i][1] >= cuboids[j][1] && 
                    cuboids[i][2] >= cuboids[j][2]) {
                    dp[i] = max(dp[i], dp[j] + cuboids[i][2]);
                }
            }
            ans = max(ans, dp[i]);
        }
        return ans;
    }
};

执行用时:12 ms, 在所有 C++ 提交中击败了74.41%的用户
内存消耗:8.8 MB, 在所有 C++ 提交中击败了72.44%的用户
复杂度分析
时间复杂度:O(n2) ,其中 n 表示长方体的个数。时间复杂度主要取决于排序与动态规划枚举,对每个长方体边的大小进行排序的总时间复杂度为 O(n),对长方体进行排序的时间为 O(nlog⁡n) ,对于每个长方体我们都需要枚举所有可以堆叠其上的长方体,需要的时间为 O(n2) ,因此总的时间复杂度为 O(n2) 。
空间复杂度: O(n),其中 n 表示长方体的个数。排序需要的栈空间为 O(log⁡n) ,存储每个长方体为底的最大高度需要的空间为 O(n),因此总的空间复杂度为 O(n)。

方法二:记忆化搜索

思路与算法

  与解法一同样的解题思路,我们还可以采用自顶向下的记忆化搜索,与方法一相比会减少无效状态,设 memo[i] 表示第 i 个长方体为顶部长方体的最大高度,我们依次尝试是否可以把当前的第 i 个长方体放置到第 j 个长方体的顶部。则此时我们可以得到递推公式如下:

1
我们求出以每个长方体为顶部的最大高度即可。

代码:

class Solution {
public:
    bool check(const vector<int> &a, const vector<int> &b) {
        return a[0] <= b[0] && a[1] <= b[1] && a[2] <= b[2];
    }

    int maxHeight(vector<vector<int>>& cuboids) {
        int n = cuboids.size();
        for (auto & v : cuboids) {
            sort(v.begin(), v.end());
        }
        sort(cuboids.begin(), cuboids.end(), [](const vector<int> & a, const vector<int> & b) {
            return a[0] + a[1] + a[2] < b[0] + b[1] + b[2];
        });

        vector<int> memo(n, -1);
        function<int(int, int)> dfs = [&](int top, int index)->int {
            if (index == cuboids.size()) {
                return 0;
            }
            if (top != -1 && memo[top] != -1) {
                return memo[top];
            }
            int height = dfs(top, index + 1);
            if (top == -1 || check(cuboids[top], cuboids[index])) {
                height = max(height, cuboids[index][2] + dfs(index, index + 1));
            }
            if (top != -1) {
                memo[top] = height;
            }
            return height;
        };
        return dfs(-1, 0);
    }
};

执行用时:12 ms, 在所有 C++ 提交中击败了74.41%的用户
内存消耗:9 MB, 在所有 C++ 提交中击败了16.14%的用户
复杂度分析
时间复杂度:O(n2),其中 n 表示长方体的个数。时间复杂度主要取决于排序与动态规划枚举,对每个长方体边的大小进行排序的总时间复杂度为 O(n),对长方体进行排序的时间为 O(nlog⁡n),对于每个长方体我们都需要枚举所有可以堆叠在其下方的长方体,需要的时间为 O(n2),因此总的时间复杂度为 O(n2)。
空间复杂度: O(n),其中 n 表示长方体的个数。排序需要的栈空间为 O(log⁡n),存储每个长方体为底的最大高度需要的空间为 O(n),递归搜索最大深度为 O(n)。因此总的空间复杂度为 O(n)。
author:力扣官方题解

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

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

相关文章

快速傅里叶变换及Python代码实现

一、前言 我想认真写好快速傅里叶变换&#xff08;Fast Fourier Transform&#xff0c;FFT&#xff09;&#xff0c;所以这篇文章会由浅到细&#xff0c;由窄到宽的讲解&#xff0c;但是傅里叶变换对于寻常人并不是很容易理解的&#xff0c;所以对于基础不牢的人我会通过前言普…

阿里巴巴2022年最新最全500道Java后端面试大全(值得收藏)

进大厂是大部分程序员的梦想&#xff0c;而进大厂的门槛也是比较高的&#xff0c;所以这里整理了一份阿里、美团、滴滴、头条等大厂面试大全其中概括的知识点有&#xff1a;Java基础、spring、springmvc、springboot、springcloud、JVM、Tomcat、dubbo、netty、zookeeper共有50…

Java中四大线程池应用及详解

线程池的思想 我们使用线程的时候就去创建一个线程&#xff0c;这样实现起来非常简便&#xff0c;但是就会有一个问题&#xff1a; 如果并发的线程数量很多&#xff0c;并且每个线程都是执行一个时间很短的任务就结束了&#xff0c;这样频繁创建线程就会大大降低系统的效率&a…

移动网络技术--名词介绍

GPRS网络制式&#xff08;General Packet Radio Service&#xff09;为“通用分组无线服务”&#xff0c;它是利用“包交换”&#xff08;Packet-Switched&#xff09;的概念所发展出的一套基于GSM系统的无线传输方式。 GGSN&#xff08;Gateway GPRS Supporting Node,网关GPR…

Nginx入门到弃坑---安装与使用篇(2)

1 下载 官网传送门下载传送门点击下载最新Windows-1.23版下载传送门点击下载最新Linux-1.23版下载传送门 2 Windows安装 2.1 环境介绍 下载完成后解压缩 目录如下 配置文件地址&#xff1a;.\nginx-1.23.2\conf\nginx.conf&#xff0c;默认配置的nginx监听的端口为80&…

监控系列(一)DM8+Prometheus+Grafana搭建

一、背景 近期进行适配&#xff0c;因用户统一监控平台使用的是promethesugrafanaaltermannger这一套&#xff0c;因此对达梦数据库进行适配对接。 目前主要有两种方式&#xff1a; 1. 部署Dem管理系统对外提供接口推送到prometheus进行采集数据&#xff0c;采集项可查看《De…

【云计算与大数据技术】分布式计算、虚拟化技术、并行编程技术等技术讲解(超详细必看)

一、分布式计算 分布式计算是一种计算方法&#xff0c;和集中式计算相对&#xff0c;随着计算的发展&#xff0c;一些应用需要巨大的计算能力才能完成&#xff0c;如果采用集中式计算则需要耗费很长的时间&#xff0c;而分布式计算将应用分解成许多更小的部分&#xff0c;分配…

文献阅读(195)物理设计/时序分析

文章目录物理设计时序分析题目&#xff1a;Intelligent Design Automation for 2.5/3D Heterogeneous SoC Integration时间&#xff1a;2020会议&#xff1a;ICCAD研究机构&#xff1a;国立台湾大学 本篇论文的主要贡献&#xff1a; 物理设计&#xff1a;包括RDL布线和板级布…

蚁群优化算法解决TSP问题(Matlab代码实现)

&#x1f468;‍&#x1f393;个人主页&#xff1a;研学社的博客 &#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜…

CSS 3万字超详细总结

文章目录1. CSS简介2. CSS的使用2.1 行内样式2.2 内部样式表2.3 外部样式表2.4 多重样式与样式优先级3. CSS选择器3.1 简单选择器3.1.1 元素选择器3.1.2 id选择器3.1.3 class选择器3.2 组合器选择器3.2.1 后代选择器3.2.2 子选择器3.2.3 相邻兄弟选择器3.2.4 通用兄弟选择器3.3…

C# 流程控制语句

一 结构化程序设计的三种基本流程 1 顺序 分支 循环 2 简单语句 最简单的语句&#xff1a;方法调用语句及赋值语句 后面有个分号 如&#xff1a; System.Console.Write("Hello World"); ba>0?a:-a; sTextBox1.Text; dint.Parse(s);注意&#xff1a;没有表达式…

SpringBoot简单优雅实现图片上传功能(超详细)

文章目录前言技术栈项目目录前端实现index.htmlscript.js后端实现MultipartFile 介绍配置文件实体类ControllerMapperService拦截器测试结果展示前言 最近有一个需求需要实现图片上传&#xff0c;因此&#xff0c;本人找到了一个可以快速实现该功能的插件mini-upload-form。在…

CAS:2374782-03-1,NOTA-FAPI-4化学试剂供应

试剂描述 NOTA-FAPI-4是FAPI-4的类似物和成纤维细胞活化蛋白&#xff08;FAP&#xff09;抑制剂。NOTA-FAPI-4可作为PET示踪剂用于检测与成纤维细胞活化蛋白相关的紊乱。 试剂基本信息 1、名称&#xff1a;NOTA-FAPI-4 2、CAS编号&#xff1a;2374782-03-1 3、分子式&#x…

Seata模式

爬虫组件分析目录概述需求&#xff1a;设计思路实现思路分析1.一、AT 模式参考资料和推荐阅读Survive by day and develop by night. talk for import biz , show your perfect code,full busy&#xff0c;skip hardness,make a better result,wait for change,challenge Survi…

_4LeetCode代码随想录算法训练营第四天-C++

_4LeetCode代码随想录算法训练营第四天-C 两两交换链表中的节点 19.删除链表的倒数第N个节点 面试题 02.07. 链表相交 142.环形链表II 24.两两交换链表中的节点 整体思路 不是简单地交换值&#xff0c;而是交换指针地指向。 终止条件为&#xff1a; cur->next ! nul…

偏微分方程重要的前置知识

现在觉得很dog 开学期末考试正好美赛。无法评论&#xff0c;无法评论。乐淘淘&#xff0c;乐淘淘。期末考试不要延迟&#xff0c;求求了或者不安排在下学期第一周也可以。。。。反正求求了&#xff0c;美赛机会难得当然&#xff0c;如果是偏微分方程的问题的话&#xff0c;其实…

springboot连接Oracle的注意点(数据库信息配置、主键精度问题、OJDBC jar包、Oracle主键自增问题)

开篇废话&#xff1a;&#xff08;前段时间因为太忙没有坚持写博客&#xff0c;导致很久没有更新&#xff0c;今天终于忙里偷闲写上一篇&#xff09; 最近做了一个项目&#xff0c;数据库用的是Oracle&#xff0c;由于之前一直用的是MySQL&#xff0c;所以在一些细节配置上不是…

详细教你用NPS搭建内网穿透服务

文章目录 前言一、NPS概述 NPS的原理 二、NPS服务器搭建 1、下载软件2、云服务器配置 2.1、防火墙配置2.2、用WinSCP远程上传服务文件2.3、使用SSH终端安装启动2.4、修改配置文件 三、客户端连接总结 前言 相信大家外出旅游或者出差都是背着轻薄本&#xff0c;如果空闲之余想…

【Dubbo3高级特性】「实战开发」适配日志框架并支持运行时动态切换使用的日志框架开发实战

日志框架适配及运行时管理 本节内容主要是针对于如何在Dubbo中适配日志框架并支持运行时动态切换使用的日志框架&#xff0c;首先前提是需要进行启动我们Dubbo服务的Qos服务&#xff0c;它主要用于作为我们的操作对应的日志切换的功能实现机制 特性说明 日志框架适配&#x…

MATLB|基于matpower优化调度的风力模型预测

&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️❤️&#x1f4a5;&#x1f4a5;&#x1f4a5;&#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清…