The Wayback Machine - https://web.archive.org/web/20250117213519/https://www.geeksforgeeks.org/flood-fill-algorithm/
Open In App

Flood Fill Algorithm

Last Updated : 16 Aug, 2024
Summarize
Comments
Improve
Suggest changes
Like Article
Like
Save
Share
Report
News Follow

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 3

Input: 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 change

Input:: 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:

C++
#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;
}
C
#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;
}
Java
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();
        }
    }
}
Python
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)))
C#
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();
        }
    }
}
JavaScript
// 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:

C++
#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;
}
C
#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;
}
Java
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();
        }
    }
}
Python
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)))
C#
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();
        }
    }
}
JavaScript
// 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.



Next Article
Article Tags :
Practice Tags :

Similar Reads

three90RightbarBannerImg