leetcode
leetcode 2801 ~ 2850
堆箱子

堆箱子

难度:

标签:

题目描述

You have a stack of n boxes, with widths wi, depths di, and heights hi. The boxes cannot be rotated and can only be stacked on top of one another if each box in the stack is strictly larger than the box above it in width, height, and depth. Implement a method to compute the height of the tallest possible stack. The height of a stack is the sum of the heights of each box.

The input use [wi, di, hi] to represents each box.

Example1:

 Input: box = [[1, 1, 1], [2, 2, 2], [3, 3, 3]]
 Output: 6

Example2:

 Input: box = [[1, 1, 1], [2, 3, 4], [2, 6, 7], [3, 4, 5]]
 Output: 10

Note:

  1. box.length <= 3000

代码结果

运行时间: 417 ms, 内存: 16.8 MB


/*
 * 思路:
 * 1. 首先,对箱子按照宽度、深度、高度进行排序。
 * 2. 然后,使用动态规划的方法,dp[i]表示以第i个箱子为最顶端箱子时的最大堆叠高度。
 * 3. 对于每个箱子,计算其最大堆叠高度时,要检查所有比它宽、深、高都小的箱子,更新最大高度。
 * 4. 最终结果为所有dp值中的最大值。
 */

import java.util.Arrays;
import java.util.Comparator;
import java.util.stream.IntStream;

public class BoxStackingStream {
    public int pileBox(int[][] box) {
        Arrays.sort(box, Comparator.<int[]>comparingInt(a -> a[0])
                                 .thenComparingInt(a -> a[1])
                                 .thenComparingInt(a -> a[2]));

        int n = box.length;
        int[] dp = new int[n];

        IntStream.range(0, n).forEach(i -> dp[i] = box[i][2]);

        IntStream.range(0, n).forEach(i ->
            IntStream.range(0, i).forEach(j -> {
                if (box[j][0] < box[i][0] && box[j][1] < box[i][1] && box[j][2] < box[i][2]) {
                    dp[i] = Math.max(dp[i], dp[j] + box[i][2]);
                }
            })
        );

        return IntStream.of(dp).max().orElse(0);
    }

    public static void main(String[] args) {
        BoxStackingStream solution = new BoxStackingStream();
        int[][] box1 = {{1, 1, 1}, {2, 2, 2}, {3, 3, 3}};
        int[][] box2 = {{1, 1, 1}, {2, 3, 4}, {2, 6, 7}, {3, 4, 5}};
        System.out.println(solution.pileBox(box1)); // 输出6
        System.out.println(solution.pileBox(box2)); // 输出10
    }
}

解释

方法:

此题解采用动态规划的思想。首先对箱子进行排序,便于后续比较。之后,定义一个数组 h,其中 h[i] 表示以第 i 个箱子为顶部箱子时能达到的最大高度。对于每个箱子 i,遍历在其之前的所有箱子 j,检查是否可以把箱子 j 堆放在箱子 i 下面(即满足 wi > wj, di > dj, hi > hj 的条件)。如果可以,则计算如果以箱子 j 为基底时的总高度,更新 h[i]。最终,遍历所有的 h[i],找到最大值即为答案。

时间复杂度:

O(n^2)

空间复杂度:

O(n)

代码细节讲解

🦆
为什么在对箱子进行排序时没有指定排序的具体规则(如按宽度、深度或高度排序)?排序的规则会如何影响算法的效果?
在题解中没有明确指定排序规则可能是因为省略了细节,或者默认按照某种标准的全面排序(例如Python中的元组排序会按照元素顺序依次比较)。排序的规则会显著影响算法的效率和简洁性。如果正确排序(例如先按宽度,然后按深度,最后按高度),可以确保在动态规划过程中,每次只需比较前面的箱子是否可以作为当前箱子的基底,从而简化比较过程并减少不必要的比较。不恰当的排序可能导致算法效率降低,因为需要额外的条件判断来确保堆叠是可行的。
🦆
动态规划中使用的数组 h[i] 表示的是以第 i 个箱子为顶部时的最大高度,这个定义是否意味着每个箱子都必须使用,还是说它们可以被跳过?
数组 h[i] 的定义并不意味着每个箱子都必须使用。它仅表示如果选择将第 i 个箱子作为顶部箱子时能达到的最大高度。在动态规划的过程中,我们会更新每个箱子作为顶部的最大可能高度,但最终的解可能不包括所有箱子。我们是在所有 h[i] 的值中选择最大的一个作为最终结果,这意味着某些箱子可以被跳过,不用于构成最高的堆叠方式。
🦆
在内层循环中,条件 wj < wi, dj < di, hj < hi 用来判断箱子 j 是否可以放在箱子 i 下面。这里的 '小于' 条件是否意味着箱体尺寸必须严格递减?如果是,这是否限制了某些可能的有效堆叠方式?
是的,条件 wj < wi, dj < di, hj < hi 的使用确实意味着箱体尺寸必须严格递减。这种条件确保了每个箱子都可以稳定地放在下一个更大的箱子上面。然而,这样的严格条件确实限制了某些可能的有效堆叠方式。例如,如果两个箱子在宽度和深度上大小相同,但高度不同,按照当前的条件,这两个箱子不能堆叠,即使实际上可能是可行的。这种情况下,可能需要调整算法,允许一定的灵活性,例如考虑非严格递减的条件,或者增加更多的逻辑来处理特殊情况。

相关问题