Connected Components
What is this?
Counting components is a 101 skill. All three problems here run the same flood fill and then ask something the count alone cannot answer: is this component enclosed, what rectangle does it occupy, and is its shape one I have already seen. The traversal is identical every time; what you record during it is the whole problem.
💡 Fun fact: Number of Distinct Islands hashes an island by recording the directions its DFS takes — and the recording is wrong without a marker on the way out of each cell. These two shapes both produce
oRRDRwith directions alone:#### ###. ..#. ..##Appending a single backtrack character when a call returns separates them, and separates every other colliding pair. It is one line, and without it the solution passes the samples and fails the judge.
🔓 The 3 problems in this chapter are free. Sign in with Google or Microsoft to start solving.
The one-line idea: the flood fill is free. Decide what to record while it runs — a border flag, two corners, or a path signature — and each of these problems becomes the same twelve lines with a different accumulator.
1. Record whether it touched the border
An island is closed if the flood fill never reaches the edge of the grid. The cleanest form removes the open ones first:
for r in range(m): # sink everything border-connected
for c in range(n):
if (r in (0, m-1) or c in (0, n-1)) and grid[r][c] == 0:
flood(r, c)
closed = 0
for r in range(m):
for c in range(n):
if grid[r][c] == 0:
flood(r, c); closed += 1 # whatever survives is enclosed
Two passes, no flags to thread through the recursion. The alternative — returning a boolean up from the DFS — works but must keep exploring after reaching the border rather than returning early, or the component is left half-marked and gets counted again.
Watch the encoding: here 0 is land and 1 is water, the reverse of the usual island problem, which catches people who typed the shape from memory.
2. Record the corners
Groups are rectangles and never touch, which means no traversal is needed at all. A cell is a top-left corner exactly when nothing is above it and nothing is to its left; from there the extent is two straight walks:
for r in range(m):
for c in range(n):
if land[r][c] == 1 and (r == 0 or land[r-1][c] == 0) \
and (c == 0 or land[r][c-1] == 0):
r2, c2 = r, c
while r2 + 1 < m and land[r2+1][c] == 1: r2 += 1
while c2 + 1 < n and land[r][c2+1] == 1: c2 += 1
out.append([r, c, r2, c2])
No visited set, no recursion, O(mn) total. This only works because the problem guarantees rectangles, and saying that out loud is the point — the guarantee is what buys the simpler algorithm, and without it you would be back to a flood fill tracking min and max row and column.
3. Record the path
def dfs(r, c, d):
if not in_bounds(r, c) or grid[r][c] == 0 or (r, c) in seen: return
seen.add((r, c)); sig.append(d)
dfs(r+1, c, 'D'); dfs(r-1, c, 'U'); dfs(r, c+1, 'R'); dfs(r, c-1, 'L')
sig.append('b') # ← the backtrack marker
Starting each island from its first cell in row-major order makes the walk deterministic, so identical shapes produce identical strings and translation is handled for free. The 'b' is what makes the encoding injective. An equally good alternative records each cell's offset from the island's first cell — (r − r0, c − c0) — as a frozen set, which needs no marker because it stores the geometry directly rather than a walk.
4. A 30-second worked example (closed islands)
grid = [[0,0,1,0,0], [0,1,0,1,0], [0,1,1,1,0]] — 0 is land, 1 is water.
The single enclosed cell is the answer, and it is enclosed only because all four of its neighbours are water. Any leak — including a diagonal one, which does not count as a connection — would have sunk it in the first pass.
5. Where you'll actually meet this
- Image segmentation. Connected-component labelling is the classic operation; "does this region touch the frame edge" decides whether an object was fully captured.
- Land and parcel systems. Bounding rectangles for contiguous plots is the farmland problem exactly.
- Sprite and asset tooling. Deduplicating identical sprites across a sheet is shape hashing.
- Medical imaging. Counting lesions of a given shape, and discarding regions clipped by the scan boundary.
- Procedural map generation. Verifying that a generated cave is enclosed, and rejecting duplicate room shapes.
6. Problems in this chapter
▶ Number of Closed Islands
Count islands not touching the border. Sink every border-connected component first, then count what survives.
Pattern: flood fill + border elimination. Target: O(mn) time, O(mn) worst-case stack.
▶ Find All Groups of Farmland
Return the corners of each rectangular group. Detect top-left corners by their empty neighbours and walk right and down.
Pattern: corner detection, no traversal. Target: O(mn) time, O(1) extra space.
▶ Number of Distinct Islands
Count islands distinct up to translation. Hash each island by its DFS path, with a marker recorded on the way out.
Pattern: canonical shape as a hash key. Target: O(mn) time.
7. Common pitfalls 🚫
- Omitting the backtrack marker in the shape signature, which silently merges genuinely different islands.
- Reading the closed-islands encoding backwards.
0is land and1is water here. - Returning early from the DFS on reaching the border, which leaves a component partly unvisited and counted twice.
- Treating diagonals as connections. All three problems are four-directional.
- Flood-filling the farmland problem when corner detection is both simpler and faster — and not saying why the rectangle guarantee allows it.
- Not normalising the shape's starting point, which makes translated copies hash differently.
- Recursing on a large grid without considering the stack; an explicit stack or an iterative BFS is safer at scale.
8. Key takeaways
- One traversal, three accumulators. The flood fill is never the interesting part.
- A canonical form is a hash key — that is the whole trick behind counting distinct shapes.
- The backtrack marker is not optional; there is a two-row counterexample without it.
- Guarantees in the statement buy simpler algorithms. Rectangles mean no traversal at all.
- Border elimination first is cleaner than threading a flag through a recursion.
- Check the land/water encoding before writing a line — it is inverted here.
- Why interviewers like it: everyone can flood fill, so the question is entirely what you choose to record while doing it.
Order: Number of Closed Islands → Find All Groups of Farmland → Number of Distinct Islands.
Find All Groups of Farmland
Core idea: The problem guarantees the groups are rectangles that never touch, and that guarantee removes the traversal entirely. A cell is a top-left corner exactly when there is no farmland above it and none to its left; from there, walk down the column and right along the row to find the far corner. No visited set, no recursion, O(mn) with O(1) extra space. Saying out loud why the rectangle guarantee permits this is the point — drop it and you are back to a flood fill tracking the minimum and maximum row and column.
Problem, rephrased
An agricultural registry processes aerial survey rasters to record every registered field. You're given a 0-indexed m x n binary matrix land, where a 0 represents a hectare of forested land and a 1 represents a hectare of farmland; the top-left corner of land is (0, 0) and the bottom-right corner is (m-1, n-1). Farmland is organized into designated groups: each group is perfectly rectangular, and no two groups are four-directionally adjacent — fields are always separated by at least a strip of forest.
Return a 2D array with one entry per group: a group with top-left corner at (r1, c1) and bottom-right corner at (r2, c2) is reported as the 4-length array [r1, c1, r2, c2] — exactly the two corners a land record needs. If there are no groups of farmland, return an empty array. The entries may be in any order.
Strip the story away and this is LeetCode 1992 — Find All Groups of Farmland: in a binary matrix whose connected components of 1s are guaranteed to be non-adjacent axis-aligned rectangles, return the [r1, c1, r2, c2] corner coordinates of every component, in any order.
Sign in to continue reading
The rest of this lesson is available with a free account. Signing in with Google or Microsoft is free.
Sign in to read the full lesson