Example 1
ready- Input
image = [ [ 1, 1, 1 ], [ 1, 1, 0 ], [ 1, 0, 1 ] ] sr = 1 sc = 1 color = 2- Expected
[ [ 2, 2, 2 ], [ 2, 2, 0 ], [ 2, 0, 1 ] ]- Why
- the start's connected 1-region changes to 2; the diagonal 1 stays put
One tap in a paint app can recolor a winding patch without touching the pixels right beside it in another patch. Your code gets to decide exactly where that color travels.
You're given a rectangular image image, a starting position (sr, sc), and a new
color. A region is the set of pixels you can reach from the start by moving up,
down, left, or right while staying on the start pixel's original color. Recolor every
pixel in that region, then return the image.
A few ground rules:
color already matches the original color, return the image unchanged.1 <= image.length <= 501 <= image[r].length <= 500 <= image[r][c], color <= 65_5360 <= sr < image.length0 <= sc < image[0].lengthHints
Save image[sr][sc] before changing anything. Every later decision compares a
neighbor with that original color, not with the new one.
Treat each matching pixel as a node with at most four neighbors. A stack or queue can carry you through every reachable matching pixel.
If the old and new colors match, stop immediately. Otherwise, recoloring a pixel can double as marking it visited.
Could you write the traversal iteratively so a long, narrow region never depends on your language's recursion limit?
Visible cases
image = [
[
1,
1,
1
],
[
1,
1,
0
],
[
1,
0,
1
]
]
sr = 1
sc = 1
color = 2[
[
2,
2,
2
],
[
2,
2,
0
],
[
2,
0,
1
]
]image = [
[
0,
0,
0
],
[
0,
1,
1
]
]
sr = 1
sc = 1
color = 1[
[
0,
0,
0
],
[
0,
1,
1
]
]image = [
[
3,
3,
8,
8
],
[
3,
8,
8,
3
],
[
3,
3,
3,
3
]
]
sr = 0
sc = 2
color = 5[
[
3,
3,
5,
5
],
[
3,
5,
5,
3
],
[
3,
3,
3,
3
]
]Interview signal
A flood fill is a traversal that spreads through neighboring cells while a rule
keeps matching. The direct version carries a stack plus a seen set. It explores every
same-colored pixel connected to the start, then writes the new color into a copied
image.
def flood_fill(
image: list[list[int]], sr: int, sc: int, color: int
) -> list[list[int]]:
original = image[sr][sc]
result = [row[:] for row in image]
stack = [(sr, sc)]
seen: set[tuple[int, int]] = set()
while stack:
row, col = stack.pop()
if (row, col) in seen or image[row][col] != original:
continue
seen.add((row, col))
result[row][col] = color
if row > 0:
stack.append((row - 1, col))
if row + 1 < len(image):
stack.append((row + 1, col))
if col > 0:
stack.append((row, col - 1))
if col + 1 < len(image[0]):
stack.append((row, col + 1))
return resultTime O(mn) — in the worst case, the region is the whole image. Space O(mn) for the copy, stack, and visited positions.
The sharper grid DFS treats the image as a graph and uses depth-first search to walk
it. Once a pixel is recolored, it no longer equals original, so the image itself tells
you that the pixel has been visited. That removes the separate set and copy.
There is one trap: when original == color, recoloring doesn't mark anything. Return
before starting the traversal or the same neighbors can be added forever.
def flood_fill(
image: list[list[int]], sr: int, sc: int, color: int
) -> list[list[int]]:
original = image[sr][sc]
if original == color:
return image
rows, cols = len(image), len(image[0])
stack = [(sr, sc)]
image[sr][sc] = color
while stack:
row, col = stack.pop()
for dr, dc in ((1, 0), (-1, 0), (0, 1), (0, -1)):
nr, nc = row + dr, col + dc
if 0 <= nr < rows and 0 <= nc < cols and image[nr][nc] == original:
image[nr][nc] = color
stack.append((nr, nc))
return imageTime O(mn) — each pixel enters the stack at most once. Space O(mn) in the worst case for the explicit DFS stack.
Ready to run.
3 cases are queued.
Visible testcase
Case 1
Expected
[
[
2,
2,
2
],
[
2,
2,
0
],
[
2,
0,
1
]
]