The problem. An image is a grid of numbers, each one a colour. Starting from the pixel (sr, sc), repaint it with color — and also every pixel connected to it (up, down, left or right) that had the same original colour, and every pixel connected to those, and so on. Return the image. It's the paint-bucket tool.
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,0,0]], sr = 0, sc = 0, color = 0
-> [[0,0,0],[0,0,0]] (already that colour: nothing changes)This is the first and most common graph pattern. The grid is a graph — each pixel joined to its four neighbours — and the region to paint is everything reachable from the start through pixels of the original colour. So: start a walk at (sr, sc), step only onto pixels of the original colour, and paint each one as you arrive.
Painting a pixel is marking it visited: once it holds the new colour it no longer matches the original, so the walk never comes back. That's why one case needs care — if color already equals the original colour, painting changes nothing and the walk would loop forever. Check for it first.
function floodFill(image, sr, sc, color) { const original = image[sr][sc]; if (original === color) return image; // already that colour: nothing to do (and no endless loop) const rows = image.length, cols = image[0].length; const paint = (r, c) => { if (r < 0 || r >= rows || c < 0 || c >= cols) return; // off the image if (image[r][c] !== original) return; // another colour: the region ends here image[r][c] = color; // paint it, which also marks it visited paint(r - 1, c); // up paint(r + 1, c); // down paint(r, c - 1); // left paint(r, c + 1); // right }; paint(sr, sc); return image;}Time O(m · n), space O(m · n). Every pixel is painted at most once. The recursion can go as deep as the region is large — a whole image of one colour means m · n nested calls.
The same walk with a queue instead of recursion, so a huge region can't overflow the call stack. Paint each pixel as it enters the queue, so it can't be added twice.
Watch the paint spread one ring at a time. Try a region that winds around, or a colour equal to the original.
const DIRS = [[-1, 0], [1, 0], [0, -1], [0, 1]]; // up, down, left, right function floodFill(image, sr, sc, color) { const original = image[sr][sc]; if (original === color) return image; // already that colour: nothing to do const rows = image.length, cols = image[0].length; const queue = [[sr, sc]]; image[sr][sc] = color; // paint on the way IN: painted means visited let head = 0; while (head < queue.length) { const [r, c] = queue[head++]; for (const [dr, dc] of DIRS) { const nr = r + dr, nc = c + dc; if (nr >= 0 && nr < rows && nc >= 0 && nc < cols && image[nr][nc] === original) { image[nr][nc] = color; // a matching neighbour joins the region queue.push([nr, nc]); } } } return image;}Time O(m · n), space O(m · n). The same work as DFS; the queue holds at most the pixels on the region's moving edge.
Both are correct and equally fast. Use DFS for short code, BFS when the grid can be huge and recursion might overflow.
[[5]] with color 3 becomes [[3]].1.DIRS.