题目描述
堆箱子。给你一堆n个箱子,箱子宽 wi、深 di、高 hi。箱子不能翻转,将箱子堆起来时,下面箱子的宽度、高度和深度必须大于上面的箱子。
实现一种方法,搭出最高的一堆箱子。箱堆的高度为每个箱子高度的总和。
输入使用数组[wi, di, hi]表示每个箱子。
示例1:
- 输入:box = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
- 输出:6
示例2:
- 输入:box = [[1, 1, 1], [2, 3, 4], [2, 6, 7], [3, 4, 5]]
- 输出:10
提示:
- 箱子的数目不大于3000个。
解题思路与代码
这道题的目的是,让我们去堆箱子,看n个箱子能够堆到的最大高度是多少。
但是呢,如何去堆这个箱子,它是有限定条件的。需要保证的是,整个箱子塔的结构,就和一个锥子一样。下面一层的箱子的长宽高,必须都大于上面一层箱子的长宽高,等于都不行。
拿到这道题的一瞬间,我脑子里面的思路是,这道题似乎可以用动态规划去解决它。果不其然,确实能用动态规划去解决。下面,就让我们看看,究竟该如何使用动态规划去解决这道题。
方法一: 动态规划 + 排序
首先我们先拿这个箱子的一个维度,去拍个序(降序)
。这样我们至少就是已经处理好一个维度的事情了。那么现在剩下的其实就是两个维度。到了两个维度以后呢,我们就可以很好的使用动态规划的思想去解决它啦~。
这里说一下,如果没有去降序,其实后面的操作,就会变得很麻烦,因为要后面要写动态规划的代码的话,必须要以一个某个维度最大的去作为基石,然后才能去逐步更新,直到最后解决问题。
我们拿动态规划的五步法,去解决这道题。
第一步,确定dp数组以及下标的含义:
- 我们定义一个一维的动态规划数组dp,其中dp[i]表示
以第i个箱子为底的最大堆箱子高度
。
第二步,确定推导公式(状态转移方程)
-
在求以第i个箱子为底的最大堆箱子高度时,需要我们去遍历箱子索引从 0 到 i – 1 的所有箱子,并且找到宽带、深度、高度都大于第i个箱子的箱子j,然后再去更新dp[i] 的值。
对于满足条件的箱子j,我们有:if(box[j][0] > box[i][0] && box[j][1] > box[i][1] && box[j][2] > box[i][2]) dp[i] = max(dp[i],dp[j] + box[i][2]);
dp[i] = max(dp[i], dp[j] + box[i][2])
;这个公式,就是我们的推导公式,也就是状态转移方程- 只要箱子j比箱子i大,我们就可以进行一次判定,到底是以i为底的dp[i]大,还是以j为底的dp[j]再加上一个箱子i更大
- 谁更大,那么更新后的dp[i]的值就等于谁。
第三步,初始化dp数组:
- 我们需要将 dp[i] 初始化为第 i 个箱子的高度,因为至少可以将每个箱子都单独成为一个箱子塔去堆放箱子:
dp[i] = box[i][2]
所以要用这样一个公式,去初始化dp数组。
第四步,确定遍历顺序:
-
首先,我们需要对箱子按照宽度、深度和高度的降序进行排序。这样,我们可以确保在遍历时,我们总是从一个更大的箱子到一个更小的箱子。
-
然后,我们从第一个箱子开始遍历,对于每个箱子 i,我们需要遍历所有小于 i 的箱子 j(即 j 从 0 到 i-1)。对于每个满足宽度、深度和高度都大于第 i 个箱子的箱子 j,我们根据递推公式更新 dp[i]。遍历完成后,dp 数组中的最大值就是最高的一堆箱子的高度。
第五步,举例推导dp数组
- 这一步的目的是让你先去纸上涂涂画画,看看自己有没有哪里可能出现了差错。检查步骤
这道题具体的代码如下:
class Solution {
public: int pileBox(vector<vector<int>>& box) {
//降序排序箱子的高度 sort(box.begin(),box.end(),[](vector<int>& a, vector<int>& b){
return a[2] > b[2];}); vector<int> dp(box.size(),0); int maxHeight = 0; for(int i = 0; i < box.size(); ++i){
dp[i] = box[i][2]; for(int j = 0; j < i; ++j) if(box[j][0] > box[i][0] && box[j][1] > box[i][1] && box[j][2] > box[i][2]) dp[i] = max(dp[i],dp[j] + box[i][2]); maxHeight = max(maxHeight,dp[i]); } return maxHeight; } };
复杂度分析
时间复杂度:
- 排序:sort 函数的时间复杂度是 O(n * log(n)),其中 n 是箱子的数量。
动态规划遍历:这段代码包含两层循环,外层循环遍历每个箱子,内层循环遍历当前箱子之前的所有箱子。因此,动态规划遍历的时间复杂度是 O(n^2)。
由于 O(n^2) 大于 O(n * log(n)),所以整段代码的时间复杂度是 O(n^2)。
空间复杂度:
- dp 数组:dp 数组的大小为 n,因此空间复杂度是 O(n)。
综上,这段代码的时间复杂度为 O(n^2),空间复杂度为 O(n)。
总结
说实话,这道题没有想象中的难。虽然说这是一道hard难度的题。但是我感觉它的难度像是middle,hhhhhh。可能是我变强了吧。继续加油,再接再厉。
今天的文章
超级面试官电子版_高级java面试问题大全及答案大全分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/81063.html