Prerequisites

Before attempting this problem, you should be comfortable with:

  • 2D Arrays/Matrices - Understanding how to traverse and modify elements in a grid
  • Depth First Search (DFS) - Recursive exploration of connected components
  • Breadth First Search (BFS) - Level-by-level traversal using a queue
  • Graph Traversal on Grids - Treating grid cells as nodes with 4-directional neighbors

Intuition

Flood fill is like using the paint bucket tool in image editors. Starting from a pixel, we want to change its color and spread to all connected pixels of the same original color. This naturally maps to a graph traversal problem where each pixel is a node connected to its four neighbors.

DFS works well here because we recursively explore as far as possible in one direction before backtracking. By changing the color as we visit each pixel, we mark it as visited, preventing infinite loops. If the new color equals the original, we skip the operation entirely to avoid unnecessary work.

Algorithm

  1. Store the original color of the starting pixel.
  2. If the original color equals the new color, return immediately (no work needed).
  3. Define a recursive dfs function that takes row and column coordinates.
  4. In dfs: if out of bounds or the pixel color does not match the original, return.
  5. Otherwise, change the pixel to the new color and recursively call dfs on all four neighbors (up, down, left, right).
  6. Start dfs from the initial coordinates and return the modified image.
class Solution:
    def floodFill(self, image: List[List[int]], sr: int, sc: int, color: int) -> List[List[int]]:
        if image[sr][sc] == color:
            return image

        m, n = len(image), len(image[0])
        dirs = [1,0,-1,0,1]

        def dfs(r, c, org):
            if not (0 <= r < m) or not (0 <= c < n) or image[r][c] != org:
                return

            image[r][c] = color
            for d in range(4):
                dfs(r + dirs[d], c + dirs[d + 1], org)

        dfs(sr, sc, image[sr][sc])
        return image

Time & Space Complexity

  • Time complexity: O(mn)O(m * n)
  • Space complexity: O(mn)O(m * n)

Where mm is the number of rows and nn is the number of columns in the image.


Intuition

BFS explores pixels level by level, processing all pixels at distance 1 from the start before those at distance 2, and so on. While DFS dives deep immediately, BFS spreads outward uniformly. Both achieve the same result for flood fill, but BFS uses a queue instead of the call stack.

The key is to color pixels when adding them to the queue, not when processing them. This prevents adding the same pixel multiple times and keeps the queue size manageable.

Algorithm

  1. Store the original color and check if it equals the new color (early return if so).
  2. Initialize a queue with the starting pixel coordinates.
  3. Immediately change the starting pixel to the new color.
  4. While the queue is not empty:
    • Dequeue a pixel.
    • For each of the four neighbors, if it is within bounds and has the original color, change it to the new color and enqueue it.
  5. Return the modified image.
class Solution:
    def floodFill(self, image: List[List[int]], sr: int, sc: int, color: int) -> List[List[int]]:
        orig = image[sr][sc]
        if orig == color:
            return image

        m, n = len(image), len(image[0])
        q = deque([(sr, sc)])
        image[sr][sc] = color
        dirs = [(1,0), (-1,0), (0,1), (0,-1)]

        while q:
            r, c = q.popleft()
            for dr, dc in dirs:
                nr, nc = r + dr, c + dc
                if 0 <= nr < m and 0 <= nc < n and image[nr][nc] == orig:
                    image[nr][nc] = color
                    q.append((nr, nc))

        return image

Time & Space Complexity

  • Time complexity: O(mn)O(m * n)
  • Space complexity: O(mn)O(m * n)

Where mm is the number of rows and nn is the number of columns in the image.


Common Pitfalls

Infinite Loop When New Color Equals Original Color

If the starting pixel already has the target color, the algorithm will infinitely revisit the same pixels since the color change that normally marks pixels as visited never happens. Always check if originalColor == newColor at the start and return immediately if true.

Not Storing the Original Color Before Modifying

The flood fill must only spread to pixels matching the original color of the starting pixel. If you check against the current pixel color after already modifying some pixels, you may either skip valid pixels or incorrectly include pixels of the new color. Store the original color in a variable before any modifications.