Python 0892.py
class Solution:
def surfaceArea(self, grid: List[List[int]]) -> int:
width = len(grid[0])
height = len(grid)
def get(x, y):
if 0 <= x < width and 0 <= y < height:
return grid[y][x]
return 0
result = 0
for y in range(height):
for x in range(width):
if get(x, y) == 0:
continue
result += 2 # top and bottom
# four sides, only if taller than neighbors
result += max(0, get(x, y) - get(x - 1, y))
result += max(0, get(x, y) - get(x + 1, y))
result += max(0, get(x, y) - get(x, y - 1))
result += max(0, get(x, y) - get(x, y + 1))
return result
Difficulty
and has an acceptance rate of about 71% (80k+ submissions).
Typical patterns to solve this problem:
- Array
- Geometry
- Math
- Matrix
AI Disclaimer
However, two years later I set up this website and used various AI tools to generate most of the walkthrough / explanations below.
See this dedicated page for more details.
Code Walkthrough
Overview
The provided implementation computes the total surface area of a 3-dimensional shape that is built from stacked unit cubes on a rectangular grid. Each cell of the input matrix contains a non-negative integer representing the height of the stack at that position. The algorithm iterates over every cell, adds the contribution of the top and bottom faces when the height is non-zero, and then adds the contribution of the four lateral faces that are exposed because the current stack is taller than its neighboring stacks. Boundary cells are treated uniformly by a helper that returns zero for out-of-range coordinates, which effectively models an empty neighbor outside the grid.
Key Steps
Determining Grid Dimensions
The first two statements extract the horizontal and vertical extents of the matrix. These values are used throughout the algorithm to bound coordinate checks.
width = len(grid[0])
height = len(grid)
Safe Neighbor Access
A nested helper function get abstracts the retrieval of a cell’s height. It returns the actual height when the coordinates lie inside the grid and returns zero otherwise. This design eliminates the need for explicit boundary checks at each neighbor comparison and naturally handles the case where a stack lies on the outer edge of the grid.
def get(x, y):
if 0 <= x < width and 0 <= y < height:
return grid[y][x]
return 0
Iterating Over All Cells
Two nested loops walk through every row and column index. The inner body is executed only when the current cell contains at least one cube; cells with height zero are skipped early, which avoids unnecessary calculations for empty positions.
for y in range(height):
for x in range(width):
if get(x, y) == 0:
continue
# further processing follows
Adding Top and Bottom Faces
When a stack is present, the algorithm immediately adds two units to the result, accounting for the topmost and bottommost faces of the column. This contribution is constant for any non-zero height.
result += 2 # top and bottom
Computing Exposed Lateral Faces
For each of the four directions-left, right, front, and back-the code calculates the height difference between the current stack and its neighbor. The max(0, …) construct ensures that only positive differences contribute, which corresponds to the portion of the side that is not covered by the adjacent column. If the neighbor is taller or equal, the contribution is zero, correctly handling cases where a side is completely hidden.
result += max(0, get(x, y) - get(x - 1, y))
result += max(0, get(x, y) - get(x + 1, y))
result += max(0, get(x, y) - get(x, y - 1))
result += max(0, get(x, y) - get(x, y + 1))
Returning the Accumulated Surface Area
After all cells have been processed, the accumulated total is returned as the final surface area.
return result
Edge Cases Handled
The algorithm gracefully manages cells that lie on the perimeter of the grid. Because the get helper returns zero for coordinates outside the valid range, a stack on the edge contributes its full side height to the surface area, as if it were adjacent to empty space. Cells with a height of zero are ignored entirely, preventing any addition of faces for empty positions. When neighboring stacks have equal height, the lateral contribution becomes zero, correctly modeling a seamless interface without any exposed area. The use of max(0, …) also protects against negative differences, ensuring that only exposed portions are counted.
Performance Optimizations
The design consolidates boundary handling into a single helper function, which reduces repetitive conditional logic inside the main loops. By skipping zero-height cells early, the algorithm avoids unnecessary neighbor checks for empty locations, saving work proportional to the number of empty cells. The use of arithmetic expressions (max(0, …)) to compute side contributions eliminates the need for explicit if statements for each direction, resulting in a tight inner loop that executes a constant amount of work per visited cell. The overall structure processes the grid in a single pass, keeping the runtime proportional to the total number of cells.
ELI5 - Simplified Explanation
Imagine a city made entirely of toy blocks sitting on a flat table. The grid is like a map that tells how many blocks are stacked in each tiny square spot on the table. Some spots have no blocks, some have one, and some might be tall towers.
To figure out how much paint is needed to cover all the outside parts of these towers, the code looks at every single spot on the map one by one. For every spot that has blocks, there is automatically a shiny top cover and a base hidden on the table, so it adds two to the total.
Then, it checks the four sides of each stack to see if they are touching any neighbor stacks. If a neighbor is shorter or empty, the exposed part of the tall tower needs paint. It does this by comparing the height of the current tower to the heights of the neighbors sitting to the left, right, above, and below. If the current tower is taller, the extra height counts as a side that needs paint. The code keeps track of all these little squares of color as it moves across the whole city map until every single visible surface has been counted.
Code Quality
Complexity Analysis
As a rule of thumb, the maximum input size for one second execution time is
- factorial: up to 10 elements
- exponential: up to 20 elements
- polynomial: a few thousand elements
- loglinear: up to 100,000 elements
- linear: a few million elements
- logarithmic: a billion elements
- constant: practically unlimited
Other Solutions
Obviously, I did that after I solved the problem myself.
In general, AlgoMonster and WalkCCC solutions are high-quality and always worth a look.
I haven't checked most of the other solutions, but they might be helpful as well.
And of course, the LeetCode forum is always a good place (or even the best) to look for alternative approaches.
(click on a column header to sort the table)
| author | |||||||||
|---|---|---|---|---|---|---|---|---|---|
| author | solutions | ||||||||
| www | AlgoMonster | C++ | Python | Java | TS | ||||
| WalkCCC | C++ | Python | Java | ||||||
| leetcode.ca | C++ | Python | Java | Go | |||||
| LeetcodeHelp | C++ | Python | Java | ||||||
| Progiez | C++ | Python | Java | ||||||
| github | BigEggStudy | C# | |||||||
| black-shadows | C++ | ||||||||
| charles-wangkai | Java | ||||||||
| everthis | JS | ||||||||
| halfrost | Go | ||||||||
| JoshCrozier | JS | ||||||||
| keineahnung2345 | C++ | ||||||||
| lkwq007 | Python | ||||||||
| lzl124631x | C++ | ||||||||
| ruoru | Rust | ||||||||
| suxrobGM | C# | ||||||||
| trung-hn | Python | ||||||||
| zfang399 | C++ | ||||||||
| AlgoMonster | C++, Python, Java, TypeScript | ||||||||
| WalkCCC | C++, Python, Java | ||||||||
| leetcode.ca | C++, Go, Java, Python | ||||||||
| LeetcodeHelp | C++, Java, Python | ||||||||
| Progiez | C++, Java, Python | ||||||||
| BigEggStudy | C# | ||||||||
| black-shadows | C++, C++ | ||||||||
| charles-wangkai | Java | ||||||||
| everthis | JavaScript | ||||||||
| halfrost | Go | ||||||||
| JoshCrozier | JavaScript | ||||||||
| keineahnung2345 | C++ | ||||||||
| lkwq007 | Python | ||||||||
| lzl124631x | C++ | ||||||||
| ruoru | Rust | ||||||||
| suxrobGM | C# | ||||||||
| trung-hn | Python | ||||||||
| zfang399 | C++ |
Videos
Solved On The Same Day
- problem 1266: Minimum Time Visiting All Points
- problem 2481: Minimum Cuts to Divide a Circle
- problem 1405: Longest Happy String
- problem 1530: Number of Good Leaf Nodes Pairs
- problem 1250: Check If It Is a Good Array
- problem 1610: Maximum Number of Visible Points
- problem 2444: Count Subarrays With Fixed Bounds
Extra
- Tech Stack - my development environment and tools
- AI - how AI helped me create this website (NOT solving the problems)
- Progress - progression over time
- Quality - code quality