title: Building Boxes
slug: building-boxes
difficulty: hard
leetcode_id: 1739
leetcode_url: https://leetcode.com/problems/building-boxes/
categories:
  - math
  - binary-search
patterns:
  - binary-search
  - greedy

function_signature: "def minimum_boxes(n: int) -> int:"

test_cases:
  visible:
    - input: { n: 3 }
      expected: 3
    - input: { n: 4 }
      expected: 3
    - input: { n: 10 }
      expected: 6
  hidden:
    - input: { n: 1 }
      expected: 1
    - input: { n: 2 }
      expected: 2
    - input: { n: 5 }
      expected: 4
    - input: { n: 6 }
      expected: 4
    - input: { n: 7 }
      expected: 5
    - input: { n: 20 }
      expected: 10

description: |
  You have a cubic storeroom where the width, length, and height of the room are all equal to `n` units. You are asked to place `n` boxes in this room where each box is a cube of unit side length. There are however some rules to placing the boxes:

  - You can place the boxes anywhere on the floor.
  - If box `x` is placed on top of box `y`, then each side of the four vertical sides of box `y` **must** either be adjacent to another box or to a wall.

  Given an integer `n`, return *the **minimum** possible number of boxes touching the floor*.

constraints: |
  - `1 <= n <= 10^9`

examples:
  - input: "n = 3"
    output: "3"
    explanation: "Place three boxes in the corner of the room, all touching the floor."
  - input: "n = 4"
    output: "3"
    explanation: "Place three boxes on the floor in the corner, with one box stacked on top of a corner box (which has all four sides supported by walls/boxes)."
  - input: "n = 10"
    output: "6"
    explanation: "Place boxes in a stepped pyramid pattern in the corner. Six boxes touch the floor, supporting four more boxes above them."

explanation:
  intuition: |
    Imagine you're stacking boxes in the corner of a room. The corner is special because it provides two walls as support. A box can only support another box on top if all four of its vertical sides are covered — either by walls or other boxes.

    Think of it like building a **stepped pyramid** in a corner. The optimal strategy is to build "layers" where:
    - Layer 1 (bottom floor): boxes form a triangular staircase pattern in the corner
    - Layer 2: boxes sit on top of layer 1, also forming a smaller triangle
    - And so on...

    The key insight is recognising that a complete pyramid of height `h` has:
    - **Floor boxes**: `1 + 2 + 3 + ... + h = h(h+1)/2` (triangular number)
    - **Total boxes**: `1 + 3 + 6 + ... + h(h+1)/2` (sum of triangular numbers = tetrahedral number)

    The total boxes in a complete pyramid is `h(h+1)(h+2)/6` — this is the h<sup>th</sup> **tetrahedral number**.

    Our strategy: find the largest complete pyramid that fits within `n` boxes, then add floor boxes one-by-one until we can fit all `n` boxes. Each additional floor box lets us stack a "column" of boxes on top of the existing structure.

  approach: |
    We solve this using **Mathematical Analysis + Greedy Addition**:

    **Step 1: Find the largest complete pyramid**

    - A complete pyramid of height `h` contains `h(h+1)(h+2)/6` total boxes
    - Use binary search or iteration to find the largest `h` where this formula gives `<= n`
    - Let `total` be the number of boxes in this complete pyramid
    - Let `floor` be the floor boxes in this pyramid: `h(h+1)/2`

    &nbsp;

    **Step 2: Handle remaining boxes**

    - Calculate `remaining = n - total` (boxes left to place)
    - If `remaining == 0`, return `floor`

    &nbsp;

    **Step 3: Add floor boxes one at a time**

    - Each new floor box at position `k` allows us to place `k` additional boxes (a column of height `k`)
    - Add floor boxes with `k = 1, 2, 3, ...` until the cumulative column heights cover `remaining`
    - This is because the k<sup>th</sup> additional floor box can support a column of `k` boxes above it

    &nbsp;

    **Step 4: Return the total floor boxes**

    - Return `floor + (number of additional floor boxes needed)`

    &nbsp;

    The greedy addition works because adding floor boxes in order (1, 2, 3, ...) maximises the boxes we can stack per floor box added.

  common_pitfalls:
    - title: Ignoring the Corner Constraint
      description: |
        Without using the corner, you'd need far more floor boxes. The corner provides two walls, meaning boxes placed against both walls can immediately support boxes on top.

        The optimal solution always uses the corner to minimise floor contact.
      wrong_approach: "Placing boxes in the middle of the room"
      correct_approach: "Build a pyramid in the corner using wall support"

    - title: Integer Overflow with Large n
      description: |
        With `n` up to `10^9`, computing `h(h+1)(h+2)` can overflow 32-bit integers. In Python this isn't an issue, but in other languages you need to use 64-bit integers or be careful with the order of operations.

        Also, the maximum pyramid height for `n = 10^9` is around 1817, so iteration is feasible.
      wrong_approach: "Using 32-bit integers for intermediate calculations"
      correct_approach: "Use 64-bit integers or Python's arbitrary precision"

    - title: Off-by-One in Additional Boxes
      description: |
        When adding floor boxes after a complete pyramid, the k<sup>th</sup> additional floor box supports a column of `k` boxes (including itself as the base counted towards remaining). Be careful about whether you're counting the floor box itself.

        The cumulative sum `1 + 2 + ... + k = k(k+1)/2` should cover `remaining`.
      wrong_approach: "Miscounting how many boxes each floor box supports"
      correct_approach: "The k-th new floor box adds capacity for k boxes total"

  key_takeaways:
    - "**Triangular and tetrahedral numbers**: Complete pyramids follow `h(h+1)(h+2)/6` — recognising this pattern is key"
    - "**Greedy completion**: After the largest complete pyramid, add floor boxes greedily to cover remaining capacity"
    - "**Geometric reasoning**: Visualising 3D stacking as layered 2D triangles simplifies the math"
    - "**Binary search for inverse functions**: Finding the largest `h` where `f(h) <= n` is a classic binary search application"

  time_complexity: "O(n^(1/3)). The pyramid height h is proportional to the cube root of n, and we iterate up to h steps."
  space_complexity: "O(1). Only a few variables for tracking the pyramid dimensions and remaining boxes."

solutions:
  - approach_name: Mathematical Analysis
    is_optimal: true
    code: |
      def minimum_boxes(n: int) -> int:
          # Step 1: Find the largest complete pyramid height
          # Tetrahedral number: h(h+1)(h+2)/6
          h = 0
          total = 0  # Total boxes in complete pyramid
          floor = 0  # Floor boxes in complete pyramid

          # Build complete layers until we exceed n
          while total + (h + 1) * (h + 2) // 2 <= n:
              h += 1
              # Add triangular number h(h+1)/2 to floor
              floor += h
              # Total boxes = sum of triangular numbers = h(h+1)(h+2)/6
              total += h * (h + 1) // 2

          # Step 2: Add individual floor boxes for remaining capacity
          remaining = n - total
          extra_floor = 0
          capacity = 0  # How many boxes we can add with extra floor boxes

          # Each new floor box k allows stacking k boxes
          while capacity < remaining:
              extra_floor += 1
              capacity += extra_floor  # The k-th floor box adds k capacity

          return floor + extra_floor
    explanation: |
      **Time Complexity:** O(n^(1/3)) — The pyramid height is O(n^(1/3)), and we iterate through layers and additional floor boxes.

      **Space Complexity:** O(1) — Only constant extra space for variables.

      We first build the largest complete pyramid possible (where each layer is a triangular arrangement). Then we greedily add floor boxes one by one. Each additional floor box at position k lets us add a column of k boxes. We stop when we have enough capacity for all n boxes.

  - approach_name: Binary Search
    is_optimal: false
    code: |
      def minimum_boxes(n: int) -> int:
          # Binary search for the largest complete pyramid height
          def tetrahedral(h: int) -> int:
              """Total boxes in a complete pyramid of height h."""
              return h * (h + 1) * (h + 2) // 6

          def triangular(k: int) -> int:
              """k-th triangular number."""
              return k * (k + 1) // 2

          # Find largest h where tetrahedral(h) <= n
          lo, hi = 0, 2000  # Max h for n=10^9 is ~1817
          while lo < hi:
              mid = (lo + hi + 1) // 2
              if tetrahedral(mid) <= n:
                  lo = mid
              else:
                  hi = mid - 1

          h = lo
          total = tetrahedral(h)
          floor = triangular(h)
          remaining = n - total

          if remaining == 0:
              return floor

          # Binary search for minimum extra floor boxes needed
          # k extra floor boxes give capacity 1+2+...+k = k(k+1)/2
          lo, hi = 1, 2000
          while lo < hi:
              mid = (lo + hi) // 2
              if triangular(mid) >= remaining:
                  hi = mid
              else:
                  lo = mid + 1

          return floor + lo
    explanation: |
      **Time Complexity:** O(log n) — Two binary searches with O(log(n^(1/3))) = O(log n) complexity.

      **Space Complexity:** O(1) — Only constant extra space.

      This approach uses binary search twice: first to find the largest complete pyramid, then to find the minimum additional floor boxes needed. While asymptotically faster, the constants are similar since n^(1/3) for n=10^9 is only ~1000. The iterative approach is often clearer and equally fast in practice.
