Flood Fill Algorithm
Given a 2D image img[][] where each img[i][j] is an integer representing the color of that pixel, also given the location of a pixel (x, y) and a new color newClr, the task is to replace the existing color of the given pixel and all the adjacent same-colored pixels with the given newClr.
Example:
Input: img[][] =
{ {1, 1, 1},
{1, 1, 0},
{1, 0, 1} }
x = 1, y = 1, newClr = 3
Output: img[][] =
{{3, 3, 3},
{3, 3, 0},
{3, 0, 1}}
Explanation: The value at arr[1][1] is 1. All connected pixels with the color 1 are replaced with 3Input: img[][] =
{ {0, 0, 0},
{0, 1, 1} }
x = 1, y = 1, newClr = 1
Output: img[][] =
{{0, 0, 0},
{0, 1 , 1}}
Explanation: Old and new colors are same, so no changeInput:: arr[][] =
{ {2, 2, 2},
{2, 2, 2}, }
x = 0, y = 0, newClr = 1
Output: img[][] =
{{1, 1, 1},
{1, 1, 1}}}
Using DFS (O(m x n)) :
- Change the color of the source row and source column with the given color
- Do DFS in four directions
- Do not forget to handle the case when previous and new colors are same.
Below is the implementation of the above approach:
#include <bits/stdc++.h>
using namespace std;
void dfs(vector<vector<int>> &img, int x, int y,
int prevClr, int newClr) {
if (img[x][y] != prevClr)
return;
// Marking it as the new color
img[x][y] = newClr;
// Moving up, right, down and left one
// by one.
int n = img.size();
int m = img[0].size();
if(x - 1 >= 0l)
dfs(img, x - 1, y, prevClr, newClr);
if(y + 1 < m)
dfs(img, x, y + 1, prevClr, newClr);
if(x + 1 < n)
dfs(img, x + 1, y, prevClr, newClr);
if(y - 1 >= 0)
dfs(img, x, y - 1, prevClr, newClr);
}
// FloodFill Function
void floodFill(vector<vector<int>>& img,
int x, int y, int newClr) {
int prevClr = img[x][y];
if (prevClr == newClr)
return;
dfs(img, x, y, prevClr, newClr);
}
// Driver code
int main() {
vector<vector<int>> img = {{1, 1, 1},
{1, 1, 0},
{1, 0, 1}};
// Co-ordinate provided by the user
int x = 1;
int y = 1;
// New color that has to be filled
int newClr = 3;
floodFill(img, x, y, newClr);
// Printing the updated img
for (int i = 0; i < img.size(); i++) {
for (int j = 0; j < img[0].size(); j++) {
cout << img[i][j] << " ";
}
cout << endl;
}
return 0;
}
#include <stdio.h>
// Function to perform DFS
void dfs(int img[3][3], int x, int y, int prevClr, int newClr) {
if (img[x][y] != prevClr)
return;
// Marking it as the new color
img[x][y] = newClr;
// Moving up, right, down and left one by one.
if (x - 1 >= 0)
dfs(img, x - 1, y, prevClr, newClr);
if (y + 1 < 3)
dfs(img, x, y + 1, prevClr, newClr);
if (x + 1 < 3)
dfs(img, x + 1, y, prevClr, newClr);
if (y - 1 >= 0)
dfs(img, x, y - 1, prevClr, newClr);
}
// FloodFill Function
void floodFill(int img[3][3], int x, int y, int newClr) {
int prevClr = img[x][y];
if (prevClr == newClr)
return;
dfs(img, x, y, prevClr, newClr);
}
// Driver code
int main() {
int img[3][3] = {{1, 1, 1}, {1, 1, 0}, {1, 0, 1}};
// Co-ordinate provided by the user
int x = 1, y = 1;
// New color that has to be filled
int newClr = 3;
floodFill(img, x, y, newClr);
// Printing the updated img
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", img[i][j]);
}
printf("\n");
}
return 0;
}
import java.util.*;
public class Main {
public static void floodFill(List<List<Integer>> img,
int x, int y, int newClr) {
int prevClr = img.get(x).get(y);
if (prevClr == newClr)
return;
dfs(img, x, y, prevClr, newClr);
}
public static void dfs(List<List<Integer>> img, int x,
int y, int prevClr, int newClr) {
// Base case: if the current pixel is not the
// same as the previous color
if (img.get(x).get(y) != prevClr) {
return;
}
// Marking it as the new color
img.get(x).set(y, newClr);
// Moving up, right, down, and left one by one
int n = img.size();
int m = img.get(0).size();
if (x - 1 >= 0) {
dfs(img, x - 1, y, prevClr, newClr);
}
if (y + 1 < m) {
dfs(img, x, y + 1, prevClr, newClr);
}
if (x + 1 < n) {
dfs(img, x + 1, y, prevClr, newClr);
}
if (y - 1 >= 0) {
dfs(img, x, y - 1, prevClr, newClr);
}
}
public static void main(String[] args) {
List<List<Integer>> img = new ArrayList<>();
img.add(Arrays.asList(1, 1, 1));
img.add(Arrays.asList(1, 1, 0));
img.add(Arrays.asList(1, 0, 1));
// Co-ordinate provided by the user
int x = 1;
int y = 1;
// New color that has to be filled
int newClr = 3;
floodFill(img, x, y, newClr);
// Printing the updated img
for (List<Integer> row : img) {
for (int val : row) {
System.out.print(val + " ");
}
System.out.println();
}
}
}
def dfs(img, x, y, prev_clr, new_clr):
# Base case: if the current pixel is not
# the same as the previous color
if img[x][y] != prev_clr:
return
# Marking it as the new color
img[x][y] = new_clr
# Moving up, right, down, and left one by one
n = len(img)
m = len(img[0])
if x - 1 >= 0:
dfs(img, x - 1, y, prev_clr, new_clr)
if y + 1 < m:
dfs(img, x, y + 1, prev_clr, new_clr)
if x + 1 < n:
dfs(img, x + 1, y, prev_clr, new_clr)
if y - 1 >= 0:
dfs(img, x, y - 1, prev_clr, new_clr)
def flood_fill(img, x, y, new_clr):
prev_clr = img[x][y]
if prev_clr == new_clr:
return
dfs(img, x, y, prev_clr, new_clr)
# Driver code
img = [
[1, 1, 1],
[1, 1, 0],
[1, 0, 1]
]
# Co-ordinate provided by the user
x = 1
y = 1
# New color that has to be filled
new_clr = 3
flood_fill(img, x, y, new_clr)
# Printing the updated img
for row in img:
print(' '.join(map(str, row)))
using System;
using System.Collections.Generic;
class Program {
// Function to perform DFS
static void Dfs(List<List<int>> img, int x, int y, int prevClr, int newClr) {
if (img[x][y] != prevClr)
return;
// Marking it as the new color
img[x][y] = newClr;
// Moving up, right, down and left one by one.
int n = img.Count;
int m = img[0].Count;
if (x - 1 >= 0)
Dfs(img, x - 1, y, prevClr, newClr);
if (y + 1 < m)
Dfs(img, x, y + 1, prevClr, newClr);
if (x + 1 < n)
Dfs(img, x + 1, y, prevClr, newClr);
if (y - 1 >= 0)
Dfs(img, x, y - 1, prevClr, newClr);
}
// FloodFill Function
static void FloodFill(List<List<int>> img, int x, int y, int newClr) {
int prevClr = img[x][y];
if (prevClr == newClr)
return;
Dfs(img, x, y, prevClr, newClr);
}
// Driver code
static void Main() {
List<List<int>> img = new List<List<int>> {
new List<int> {1, 1, 1},
new List<int> {1, 1, 0},
new List<int> {1, 0, 1}
};
// Co-ordinate provided by the user
int x = 1;
int y = 1;
// New color that has to be filled
int newClr = 3;
FloodFill(img, x, y, newClr);
// Printing the updated img
foreach (var row in img) {
foreach (var val in row) {
Console.Write(val + " ");
}
Console.WriteLine();
}
}
}
// Function to perform DFS
function dfs(img, x, y, prevClr, newClr) {
if (img[x][y] !== prevClr)
return;
// Marking it as the new color
img[x][y] = newClr;
// Moving up, right, down, and left one by one.
const n = img.length;
const m = img[0].length;
if (x - 1 >= 0)
dfs(img, x - 1, y, prevClr, newClr);
if (y + 1 < m)
dfs(img, x, y + 1, prevClr, newClr);
if (x + 1 < n)
dfs(img, x + 1, y, prevClr, newClr);
if (y - 1 >= 0)
dfs(img, x, y - 1, prevClr, newClr);
}
// FloodFill Function
function floodFill(img, x, y, newClr) {
const prevClr = img[x][y];
if (prevClr === newClr)
return;
dfs(img, x, y, prevClr, newClr);
}
// Driver code
const img = [
[1, 1, 1],
[1, 1, 0],
[1, 0, 1]
];
// Co-ordinate provided by the user
const x = 1, y = 1;
// New color that has to be filled
const newClr = 3;
floodFill(img, x, y, newClr);
// Printing the updated img
img.forEach(row => {
console.log(row.join(' '));
});
Output
3 3 3 3 3 0 3 0 1
Time Complexity: O(m*n)
Auxiliary Space: O(m*n), due to the recursive call stack.
Further Optimizations to the above code. We can check for the condition if (img[x][y] != prevClr) before making recursive calls. This will save some unnecessary recursive calls for the adjacent of the last nodes.
Using BFS (O(m x n)) :
The idea is to use BFS traversal to replace the color with the new color.
- Create an empty queue letâs say Q.
- Push the starting location of the pixel as given in the input and apply the replacement color to it.
- Iterate until Q is not empty and pop the front node (pixel position).
- Check the pixels adjacent to the current pixel and push them into the queue if valid (had not been colored with replacement color).
Below is the implementation of the above approach:
#include <bits/stdc++.h>
using namespace std;
// Fill the image img[x][y] and all its same colored
// adjacent with the given new color
void floodFill(vector<vector<int>>& img, int x,
int y, int newClr) {
queue<pair<int, int>> q;
// Rows and columns of the display
int m = img.size();
int n = img[0].size();
int prevClr = img[x][y];
if (prevClr == newClr)
return;
// Append the position of starting pixel
// of the component
q.push({x, y});
img[x][y] = newClr;
// While the queue is not empty i.e. the
// whole component having prevClr color
// is not colored with newClr color
while (!q.empty()) {
// Dequeue the front node
x = q.front().first;
y = q.front().second;
q.pop();
// Check if the adjacent pixels are valid
// and enqueue
if (x + 1 < m && img[x + 1][y] == prevClr) {
img[x + 1][y] = newClr;
q.push({x + 1, y});
}
if (x - 1 >= 0 && img[x - 1][y] == prevClr) {
img[x - 1][y] = newClr;
q.push({x - 1, y});
}
if (y + 1 < n && img[x][y + 1] == prevClr) {
img[x][y + 1] = newClr;
q.push({x, y + 1});
}
if (y - 1 >= 0 && img[x][y - 1] == prevClr) {
img[x][y - 1] = newClr;
q.push({x, y - 1});
}
}
}
int main() {
vector<vector<int>> img = {
{ 1, 1, 1 },
{ 1, 1, 0 },
{ 1, 0, 1 }
};
int x = 1, y = 1;
int newClr = 3;
floodFill(img, x, y, newClr);
// Printing the updated img
for (const auto& row : img) {
for (int val : row) {
cout << val << " ";
}
cout << endl;
}
return 0;
}
#include <stdio.h>
#include <stdlib.h>
#define M 3
#define N 3
// Fill the image img[x][y] and all its same colored
// adjacent with the given new color
void floodFill(int img[M][N], int x, int y, int newClr) {
int m = M, n = N;
int prevClr = img[x][y];
if (prevClr == newClr) return;
typedef struct { int x, y; } Point;
Point queue[1000];
int front = 0, rear = 0;
queue[rear++] = (Point){x, y};
img[x][y] = newClr;
while (front < rear) {
Point p = queue[front++];
x = p.x; y = p.y;
// Check if the adjacent pixels are valid and enqueue
if (x + 1 < m && img[x + 1][y] == prevClr) {
img[x + 1][y] = newClr;
queue[rear++] = (Point){x + 1, y};
}
if (x - 1 >= 0 && img[x - 1][y] == prevClr) {
img[x - 1][y] = newClr;
queue[rear++] = (Point){x - 1, y};
}
if (y + 1 < n && img[x][y + 1] == prevClr) {
img[x][y + 1] = newClr;
queue[rear++] = (Point){x, y + 1};
}
if (y - 1 >= 0 && img[x][y - 1] == prevClr) {
img[x][y - 1] = newClr;
queue[rear++] = (Point){x, y - 1};
}
}
}
int main() {
int img[M][N] = {
{ 1, 1, 1 },
{ 1, 1, 0 },
{ 1, 0, 1 }
};
int x = 1, y = 1;
int newClr = 3;
floodFill(img, x, y, newClr);
// Printing the updated img
for (int i = 0; i < M; i++) {
for (int j = 0; j < N; j++) {
printf("%d ", img[i][j]);
}
printf("\n");
}
return 0;
}
import java.util.LinkedList;
import java.util.Queue;
public class GfG {
// Fill the image img[x][y] and all its same colored
// adjacent with the given new color
public static void floodFill(int[][] img, int x,
int y, int newClr) {
Queue<int[]> q = new LinkedList<>();
// Rows and columns of the display
int m = img.length;
int n = img[0].length;
int prevClr = img[x][y];
if (prevClr == newClr)
return;
// Append the position of the starting
// pixel of the component
q.add(new int[]{x, y});
img[x][y] = newClr;
// While the queue is not empty, i.e., the
// whole component having prevClr color
// is not colored with newClr color
while (!q.isEmpty()) {
// Dequeue the front node
int[] pos = q.poll();
x = pos[0];
y = pos[1];
// Check if the adjacent pixels are valid and enqueue
if (x + 1 < m && img[x + 1][y] == prevClr) {
img[x + 1][y] = newClr;
q.add(new int[]{x + 1, y});
}
if (x - 1 >= 0 && img[x - 1][y] == prevClr) {
img[x - 1][y] = newClr;
q.add(new int[]{x - 1, y});
}
if (y + 1 < n && img[x][y + 1] == prevClr) {
img[x][y + 1] = newClr;
q.add(new int[]{x, y + 1});
}
if (y - 1 >= 0 && img[x][y - 1] == prevClr) {
img[x][y - 1] = newClr;
q.add(new int[]{x, y - 1});
}
}
}
public static void main(String[] args) {
int[][] img = {
{ 1, 1, 1 },
{ 1, 1, 0 },
{ 1, 0, 1 }
};
int x = 1, y = 1;
int newClr = 3;
floodFill(img, x, y, newClr);
// Printing the updated img
for (int[] row : img) {
for (int val : row) {
System.out.print(val + " ");
}
System.out.println();
}
}
}
from collections import deque
def floodFill(img, x, y, newClr):
q = deque()
# Rows and columns of the display
m = len(img)
n = len(img[0])
prevClr = img[x][y]
if prevClr == newClr:
return
# Append the position of the starting pixel
# of the component
q.append((x, y))
img[x][y] = newClr
# While the queue is not empty, i.e., the whole
# component having prevClr color
# is not colored with newClr color
while q:
# Dequeue the front node
x, y = q.popleft()
# Check if the adjacent pixels are valid and enqueue
if x + 1 < m and img[x + 1][y] == prevClr:
img[x + 1][y] = newClr
q.append((x + 1, y))
if x - 1 >= 0 and img[x - 1][y] == prevClr:
img[x - 1][y] = newClr
q.append((x - 1, y))
if y + 1 < n and img[x][y + 1] == prevClr:
img[x][y + 1] = newClr
q.append((x, y + 1))
if y - 1 >= 0 and img[x][y - 1] == prevClr:
img[x][y - 1] = newClr
q.append((x, y - 1))
# Driver code
img = [
[1, 1, 1],
[1, 1, 0],
[1, 0, 1]
]
x = 1
y = 1
newClr = 3
floodFill(img, x, y, newClr)
# Printing the updated img
for row in img:
print(' '.join(map(str, row)))
using System;
using System.Collections.Generic;
class Program {
// Fill the image img[x][y] and all its same colored
// adjacent with the given new color
static void FloodFill(int[,] img, int x, int y, int newClr) {
Queue<(int, int)> q = new Queue<(int, int)>();
int m = img.GetLength(0);
int n = img.GetLength(1);
int prevClr = img[x, y];
if (prevClr == newClr) return;
// Append the position of starting pixel
q.Enqueue((x, y));
img[x, y] = newClr;
while (q.Count > 0) {
(x, y) = q.Dequeue();
// Check if the adjacent pixels are valid and enqueue
if (x + 1 < m && img[x + 1, y] == prevClr) {
img[x + 1, y] = newClr;
q.Enqueue((x + 1, y));
}
if (x - 1 >= 0 && img[x - 1, y] == prevClr) {
img[x - 1, y] = newClr;
q.Enqueue((x - 1, y));
}
if (y + 1 < n && img[x, y + 1] == prevClr) {
img[x, y + 1] = newClr;
q.Enqueue((x, y + 1));
}
if (y - 1 >= 0 && img[x, y - 1] == prevClr) {
img[x, y - 1] = newClr;
q.Enqueue((x, y - 1));
}
}
}
static void Main() {
int[,] img = {
{ 1, 1, 1 },
{ 1, 1, 0 },
{ 1, 0, 1 }
};
int x = 1, y = 1;
int newClr = 3;
FloodFill(img, x, y, newClr);
// Printing the updated img
for (int i = 0; i < img.GetLength(0); i++) {
for (int j = 0; j < img.GetLength(1); j++) {
Console.Write(img[i, j] + " ");
}
Console.WriteLine();
}
}
}
// Fill the image img[x][y] and all its same colored
// adjacent with the given new color
function floodFill(img, x, y, newClr) {
const q = [];
const m = img.length;
const n = img[0].length;
const prevClr = img[x][y];
if (prevClr === newClr) return;
q.push({ x, y });
img[x][y] = newClr;
while (q.length > 0) {
const { x, y } = q.shift();
// Check if the adjacent pixels are valid and enqueue
if (x + 1 < m && img[x + 1][y] === prevClr) {
img[x + 1][y] = newClr;
q.push({ x: x + 1, y });
}
if (x - 1 >= 0 && img[x - 1][y] === prevClr) {
img[x - 1][y] = newClr;
q.push({ x: x - 1, y });
}
if (y + 1 < n && img[x][y + 1] === prevClr) {
img[x][y + 1] = newClr;
q.push({ x, y: y + 1 });
}
if (y - 1 >= 0 && img[x][y - 1] === prevClr) {
img[x][y - 1] = newClr;
q.push({ x, y: y - 1 });
}
}
}
// Test the flood fill function
const img = [
[1, 1, 1],
[1, 1, 0],
[1, 0, 1]
];
const x = 1, y = 1, newClr = 3;
floodFill(img, x, y, newClr);
// Printing the updated img
img.forEach(row => {
console.log(row.join(' '));
});
Output
3 3 3 3 3 0 3 0 1
Time Complexity: O(m * n)
Auxiliary Space: O(m * n)
The BFS approach would work better in general as it does not require overhead of recursion.


