Want Help Cracking FAANG?

(Then click this)

×
Back to Question Bank

1739. Building Boxes - Leetcode Solution

Problem Description

The "Building Boxes" problem asks you to determine the minimum number of boxes required to build a pyramid-like structure that can contain at least n unit cubes. The structure is built in layers, where each layer forms a rectangle aligned with the floor, and each box must be supported either by the floor or by boxes directly beneath it. The goal is to find the least number of boxes needed so that all n cubes fit while obeying the stacking rules.

  • Each box is a unit cube.
  • You can stack boxes on top of each other, but a box must be supported by either the floor or by boxes below it.
  • The structure is built from the bottom up, and each new box must be placed on the floor or on top of other boxes.
  • The input is a single integer n (1 ≤ n ≤ 109).
  • The output is the minimum number of boxes needed to contain all n cubes.

Thought Process

At first glance, you might think of simply stacking boxes one on top of the other, but this is inefficient. The problem hints at using a pyramid or layered approach, which is more space-efficient.

The key insight is that the optimal way to arrange the boxes is to build a 3D pyramid with a triangular base. Each layer forms a triangle, and each new layer sits above the previous one, using fewer boxes. We want to maximize the number of boxes per layer while minimizing the total used to reach at least n cubes.

Brute-force would try every possible arrangement, but given the constraints, this would be too slow. Instead, we should look for patterns in the way layers are built and how many boxes each configuration can hold, then use mathematical formulas to quickly find the answer.

Solution Approach

To solve this efficiently, we use the properties of 3D pyramids with triangular bases:

  • Step 1: Recognize that the maximum number of cubes you can stack in k layers forms a 3D pyramid. The total number of cubes in this pyramid is the sum of the first k triangular numbers.
  • Step 2: The k-th triangular number is T(k) = k * (k + 1) / 2. The sum of the first k triangular numbers is P(k) = k * (k + 1) * (k + 2) / 6.
  • Step 3: Use binary search to find the largest k such that P(k) ≤ n. This gives the maximum number of complete layers you can build.
  • Step 4: After building k layers, you may have some cubes left (remaining = n - P(k)). These must be added on top of the existing structure, and each new box must be supported by the floor or existing boxes.
  • Step 5: To minimize the number of extra boxes, fill the base layer (which has k*(k+1)/2 boxes) with the remaining cubes, one per box, until all are used.
  • Step 6: The answer is the total number of boxes used: those in the full pyramid plus the extra boxes needed for the leftover cubes.

We use binary search for efficiency, and the triangular/pyramidal number formulas to avoid iterating through all possibilities.

Example Walkthrough

Let's say n = 10:

  • Step 1: Calculate layers:
    • For k = 1: P(1) = 1
    • For k = 2: P(2) = 4
    • For k = 3: P(3) = 10
    • For k = 4: P(4) = 20 (too large)
    So, we can build 3 complete layers with 10 cubes.
  • Step 2: Remaining cubes: 10 - 10 = 0.
  • Step 3: Total boxes used is the number in the full pyramid: 6 (for base) + 3 (second layer) + 1 (top) = 10.
  • Step 4: Since there are no remaining cubes, the answer is 6 (base) + 3 + 1 = 10.

For n = 15, after building 3 layers (using 10 cubes), we have 5 cubes left. We fill 5 more boxes on the base layer, one per box, so the answer is 6 (base) + 3 + 1 + 5 = 15.

Time and Space Complexity

  • Brute-Force Approach: O(n), since you might try every possible arrangement of boxes.
  • Optimized Approach: O(log n) due to the binary search for the number of layers, and O(1) for the arithmetic calculations. No extra data structures are needed, so space complexity is O(1).

The optimized method is much faster and can handle the largest constraints efficiently.

Summary

The "Building Boxes" problem is elegantly solved by recognizing the structure as a 3D triangular pyramid and using mathematical formulas for triangular and pyramidal numbers. By applying binary search, we efficiently determine the maximum number of complete layers, then fill any remaining cubes in the most optimal way. This approach leverages both combinatorial insight and algorithmic efficiency, making it both fast and easy to understand.

Code Implementation

class Solution:
    def minimumBoxes(self, n: int) -> int:
        # Helper: pyramidal number
        def pyramid(k):
            return k * (k + 1) * (k + 2) // 6
        
        # Binary search for largest k with pyramid(k) <= n
        left, right = 1, int((6*n)**(1/3)) + 2
        while left < right:
            mid = (left + right) // 2
            if pyramid(mid) <= n:
                left = mid + 1
            else:
                right = mid
        k = left - 1
        used = pyramid(k)
        remain = n - used
        
        # Now fill the base layer
        base = k * (k + 1) // 2
        if remain == 0:
            return base
        # Find min extra boxes to cover remain
        l, r = 1, base + 1
        while l < r:
            m = (l + r) // 2
            if m * (m + 1) // 2 >= remain:
                r = m
            else:
                l = m + 1
        return base + l
      
class Solution {
public:
    int minimumBoxes(int n) {
        auto pyramid = [](long long k) {
            return k * (k + 1) * (k + 2) / 6;
        };
        long long left = 1, right = 2000;
        while (left < right) {
            long long mid = (left + right) / 2;
            if (pyramid(mid) <= n)
                left = mid + 1;
            else
                right = mid;
        }
        long long k = left - 1;
        long long used = pyramid(k);
        long long remain = n - used;
        long long base = k * (k + 1) / 2;
        if (remain == 0) return base;
        long long l = 1, r = base + 1;
        while (l < r) {
            long long m = (l + r) / 2;
            if (m * (m + 1) / 2 >= remain)
                r = m;
            else
                l = m + 1;
        }
        return base + l;
    }
};
      
class Solution {
    public int minimumBoxes(int n) {
        // Helper: pyramidal number
        long left = 1, right = 2000;
        while (left < right) {
            long mid = (left + right) / 2;
            long pyramid = mid * (mid + 1) * (mid + 2) / 6;
            if (pyramid <= n)
                left = mid + 1;
            else
                right = mid;
        }
        long k = left - 1;
        long used = k * (k + 1) * (k + 2) / 6;
        long remain = n - used;
        long base = k * (k + 1) / 2;
        if (remain == 0) return (int)base;
        long l = 1, r = base + 1;
        while (l < r) {
            long m = (l + r) / 2;
            if (m * (m + 1) / 2 >= remain)
                r = m;
            else
                l = m + 1;
        }
        return (int)(base + l);
    }
}
      
var minimumBoxes = function(n) {
    function pyramid(k) {
        return k * (k + 1) * (k + 2) / 6;
    }
    let left = 1, right = 2000;
    while (left < right) {
        let mid = Math.floor((left + right) / 2);
        if (pyramid(mid) <= n)
            left = mid + 1;
        else
            right = mid;
    }
    let k = left - 1;
    let used = pyramid(k);
    let remain = n - used;
    let base = k * (k + 1) / 2;
    if (remain === 0) return base;
    let l = 1, r = base + 1;
    while (l < r) {
        let m = Math.floor((l + r) / 2);
        if (m * (m + 1) / 2 >= remain)
            r = m;
        else
            l = m + 1;
    }
    return base + l;
};