Skip to content
← All posts

Surface Area of 3D Shapes: Grid Geometry

4 min read
leetcodeproblemeasyarraysmathmatrix

LeetCode 892: Surface Area of 3D Shapes gives you an n x n grid where grid[i][j] represents the number of unit cubes stacked at position (i, j). These stacks sit on a flat surface, forming a 3D shape. Your job is to compute the total exposed surface area of the entire shape.

At first, it feels like you need to think in three dimensions, tracking which faces are visible from every angle. But the real trick is to work cell by cell and think about overlaps between neighbors. Once you see the pattern, the solution is a single pass through the grid with some simple arithmetic.

Grid: [[1, 2], [3, 4]]Each cell value = height of stacked cubescol 0col 1row 0row 11234v=1: 4(1)+2 = 6v=2: 4(2)+2 = 10v=3: 4(3)+2 = 14v=4: 4(4)+2 = 18Each column of height v (if v > 0):Contributes 4v + 2 faces in isolationv faces on each of 4 sides + 1 top + 1 bottomColumn of height 3 in isolation: 4(3) + 2 = 14 faces3top: 1bottom: 1left: 3right: 3front: 3back: 3Adjacent columns hide shared facesSubtract 2 * min(h1, h2) per neighbor pair12overlap = 2*min(1,2) = 2
A column of height v contributes 4v + 2 faces alone. Adjacent columns hide 2 * min(h1, h2) faces between them.

Counting faces: the core idea

Consider a single column of v cubes sitting in isolation. How many faces does it expose?

  • Top and bottom: exactly 1 face each, regardless of height. That gives you 2 faces.
  • Four sides: each side of the column is v unit squares tall. That gives you 4 * v faces.

So a single column of height v contributes 4 * v + 2 faces when it stands alone.

Now think about what happens when two adjacent columns touch. If column A has height h1 and column B has height h2, the shorter column presses against the taller one. The overlapping area on each side equals min(h1, h2) faces. Since both columns lose those faces (one on each side of the shared wall), the total faces removed is 2 * min(h1, h2).

The full formula becomes:

surface_area = sum(4 * v + 2 for each cell with v > 0)
             - sum(2 * min(a, b) for each pair of adjacent cells)

You only need to check each pair once. Scanning right and down from every cell covers all adjacent pairs without double counting.

The solution

def surfaceArea(grid: list[list[int]]) -> int:
    n = len(grid)
    area = 0

    for i in range(n):
        for j in range(n):
            if grid[i][j] > 0:
                area += 4 * grid[i][j] + 2
            if i + 1 < n:
                area -= 2 * min(grid[i][j], grid[i + 1][j])
            if j + 1 < n:
                area -= 2 * min(grid[i][j], grid[i][j + 1])

    return area

For each cell, you add its isolated contribution (if the height is positive), then subtract the overlap with the neighbor to the right and the neighbor below. That is the entire algorithm.

Step-by-step walkthrough

Step 1: Base contribution for each cell

col 0col 1row 0row 112344v + 2:(0,0) v=1: 6(0,1) v=2: 10(1,0) v=3: 14(1,1) v=4: 18Total = 48

For each cell with height v > 0, start with 4v + 2 faces: v faces on each of 4 sides, plus top and bottom. Sum of all base contributions = 6 + 10 + 14 + 18 = 48.

Step 2: Cell (0,0), v=1, check right and down neighbors

1234Overlap:right: 2*min(1,2) = 2down: 2*min(1,3) = 2Subtract 4

Right neighbor (0,1) has height 2. Overlap = 2*min(1,2) = 2. Down neighbor (1,0) has height 3. Overlap = 2*min(1,3) = 2. Total overlap for this cell = 4.

Step 3: Cell (0,1), v=2, check right and down neighbors

1234Overlap:right: none (edge)down: 2*min(2,4) = 4Subtract 4

No right neighbor (edge of grid). Down neighbor (1,1) has height 4. Overlap = 2*min(2,4) = 4. Total overlap for this cell = 4.

Step 4: Cell (1,0), v=3, check right and down neighbors

1234Overlap:right: 2*min(3,4) = 6down: none (edge)Subtract 6

Right neighbor (1,1) has height 4. Overlap = 2*min(3,4) = 6. No down neighbor (edge of grid). Total overlap for this cell = 6.

Step 5: Cell (1,1), v=4, check right and down neighbors

1234Overlap:right: none (edge)down: none (edge)Subtract 0

No right neighbor, no down neighbor (corner of grid). Nothing to subtract for this cell.

Step 6: Final calculation

Base: 48-Overlap: 14=SA = 346+10+14+184+4+6+048 - 14

Base contributions: 6 + 10 + 14 + 18 = 48. Total overlap: 4 + 4 + 6 + 0 = 14. Surface area = 48 - 14 = 34.

Complexity analysis

ApproachTimeSpace
Grid scanO(n^2)O(1)

Time: You visit every cell once and do constant work per cell (at most two neighbor comparisons). That is O(n^2) for an n x n grid.

Space: You use a single integer accumulator. No extra arrays, no recursion. That is O(1).

Building blocks

1. Grid neighbor traversal

The core mechanic here is scanning each cell and comparing it against its right and down neighbors. This "only check right and down" trick avoids double counting: every pair of adjacent cells gets processed exactly once. You will see this same traversal pattern in Island Perimeter, Number of Islands, and many other grid problems.

for i in range(n):
    for j in range(n):
        if j + 1 < n:
            # process (i,j) and (i,j+1) as a horizontal pair
        if i + 1 < n:
            # process (i,j) and (i+1,j) as a vertical pair

2. Overlap subtraction

When two values share a boundary, the hidden area equals the minimum of the two. This min(a, b) pattern shows up whenever you need to count "how much is blocked." In this problem, min(h1, h2) tells you how many unit squares of wall are hidden on each side. Multiplying by 2 accounts for both touching surfaces. The same idea appears in problems involving water trapped between bars, overlapping intervals, and rectangle intersection.

Edge cases

  • Single cell: a 1x1 grid with value v. No neighbors, so the surface area is simply 4v + 2. If v is 0, the area is 0.
  • All zeros: every cell is 0. No cubes exist, so the surface area is 0. The v > 0 check ensures you do not add the top and bottom for empty cells.
  • Uniform height: every cell has the same value k. Each cell contributes 4k + 2, and each adjacent pair removes 2k. For an n x n grid, that works out to n^2 * (4k + 2) - 2 * (2 * n * (n - 1)) * k total faces.

From understanding to recall

The key insight here fits in one sentence: each column contributes 4v + 2 faces, and each neighbor pair hides 2 * min(h1, h2) faces. If you can recall that formula, the code writes itself in under a minute.

What trips people up under pressure is forgetting to handle the v > 0 guard (empty cells should not contribute the top and bottom faces) or accidentally double-counting neighbor pairs by checking all four directions. Practice writing the solution from scratch: the nested loop, the base contribution, the two neighbor subtractions. After a few spaced reps, the "right and down only" pattern will be automatic.

Surface area counting and neighbor overlap subtraction are two of roughly 60 reusable building blocks that cover hundreds of LeetCode problems. Drilling each one individually with spaced repetition is far more effective than grinding random problems.

Related posts