Open In App

Flood Fill Algorithm

Last Updated : 11 Apr, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

You are given a 2D grid image[][], where each image[i][j] represents the color of a pixel in the image. Also provided is a coordinate(sr, sc) representing the starting pixel (row and column) and a new color value newColor.

Your task is to perform a flood fill starting from the pixel (sr, sc), changing its color and the color of all connected pixels that have the same original color. Two pixels are considered connected if they are adjacent horizontally or vertically (not diagonally) and have the same original color.

Example: 

Input: image = [[1, 1, 1, 0], [0, 1, 1, 1], [1, 0, 1, 1]], sr = 1, sc = 2, newColor = 2

111

Output: [[2, 2, 2, 0], [0, 2, 2, 2], [1, 0, 2,2]]

222

Explanation: Starting from pixel (1, 2) with value 1, flood fill updates all connected pixels (up, down, left, right) with value 1 to 2, resulting in [[2, 2, 2, 0], [0, 2, 2, 2], [1, 0, 2, 2]].

Input: image = [[0, 1, 0], [0, 1, 0]], sr = 0, sc = 1, newColor = 0
Output: [[0, 0, 0], [0, 0, 0]]
Explanation: Starting from pixel (1, 2) with value 1, flood fill updates all connected pixels (up, down, left, right) with value 1 to 0, resulting in [[0, 0, 0], [0, 0, 0]].

[Approach 1] Using Depth-First Search – O(m * n) Time and O(m * n) Space

The idea is to use Depth-First Search (DFS) to explore and update all connected pixels that share the same original color (color of image[sr][sc]). Starting from the given pixel, DFS recursively checks its adjacent pixels in all four directions—up, down, left, and right. If an adjacent pixel matches the original color, it is updated to the new color, and the DFS continues from that pixel. If not, the algorithm backtracks. This process continues until all connected pixels of the same color are filled with the new color, effectively updating the entire connected component.

Step-by-Step Implementation :

  • Store the original color at the starting pixel (sr, sc) as this will help in identifying which connected pixels need to be changed..
  • Define a DFS function that takes the current pixel’s row and column as parameters.
  • In the DFS function, if the current pixel is out of bounds or doesn’t match the original color, return (backtrack); otherwise, update its color to newColor and continue the recursion.
  • Recursively call DFS for all four adjacent directions:
    • Up: (row - 1, col), Down: (row + 1, col), Left: (row, col - 1), Right: (row, col + 1)
  • Start DFS from the starting pixel (sr, sc).
  • Once DFS completes, return the updated image.
C++
#include <iostream>
#include <vector>
using namespace std;

// Helper function for Depth-First Search (DFS)
void dfs(vector<vector<int>>& image, int x, 
         int y, int oldColor, int newColor) {
    
    // Base case: check boundary conditions and color mismatch
    if (x < 0 || x >= image.size() || 
        y < 0 || y >= image[0].size() || 
        image[x][y] != oldColor) {
    // Backtrack if pixel is out of bounds or color doesn't match
        return; 
    }

    // Update the color of the current pixel
    image[x][y] = newColor;

    // Recursively visit all 4 connected neighbors
    dfs(image, x + 1, y, oldColor, newColor); 
    dfs(image, x - 1, y, oldColor, newColor); 
    dfs(image, x, y + 1, oldColor, newColor); 
    dfs(image, x, y - 1, oldColor, newColor); 
}

// Main flood fill function
vector<vector<int>> floodFill(
    vector<vector<int>>& image, int sr, 
    int sc, int newColor) {

    // If the starting pixel already has the new color,
    // no changes are needed
    if (image[sr][sc] == newColor) {
        return image;
    }

    // Call DFS to start filling from the source pixel
    int oldColor = image[sr][sc]; // Store original color
    dfs(image, sr, sc, oldColor, newColor);

    return image; // Return the updated image
}

// Driver code to test the flood fill function
int main() {
    // Input image (2D grid)
    vector<vector<int>> image = {
        {1, 1, 1, 0},
        {0, 1, 1, 1},
        {1, 0, 1, 1}
    };
    
    // Starting pixel (row, col)
    int sr = 1, sc = 2;
    
    // New color to apply
    int newColor = 2;        

    // Perform flood fill and get the result
    vector<vector<int>> result = floodFill(image, sr, sc, newColor);

    // Print the updated image
    for (auto& row : result) {
        for (auto& pixel : row) {
            cout << pixel << " ";
        }
        cout << "\n";
    }
    return 0;
}
Java
import java.util.*;

class GfG {

    // Helper method for DFS traversal
    static void dfs(int[][] image, int x, int y, 
                        int oldColor, int newColor){

        // Base case: check for out-of-bound indices or mismatched color
        if (x < 0 || x >= image.length || 
            y < 0 || y >= image[0].length || 
            image[x][y] != oldColor) {
            return; // Backtrack if invalid
        }

        // Change the color of the current pixel
        image[x][y] = newColor;

        // Recursively call DFS in all four directions
        dfs(image, x + 1, y, oldColor, newColor); 
        dfs(image, x - 1, y, oldColor, newColor);
        dfs(image, x, y + 1, oldColor, newColor); 
        dfs(image, x, y - 1, oldColor, newColor); 
        
    }

    // Main function to perform flood fill
    static int[][] floodFill(int[][] image, int sr, int sc, int newColor){

        // If the starting pixel already has the new color, no need 
        // to process
        if (image[sr][sc] == newColor) {
            return image;
        }

        // Call DFS with the original color of the starting pixel
        dfs(image, sr, sc, image[sr][sc], newColor);

        // Return the updated image
        return image;
    }

    // Driver code to test the flood fill function
    public static void main(String[] args) {

        // Define the image matrix
        int[][] image = {
            {1, 1, 1, 0},
            {0, 1, 1, 1},
            {1, 0, 1, 1}
        };

        // Starting pixel and the new color
        int sr = 1, sc = 2, newColor = 2;

        // Perform flood fill
        int[][] result = floodFill(image, sr, sc, newColor);

        for (int[] row : result) {
            for (int pixel : row) {
                System.out.print(pixel + " ");
            }
            System.out.println();
        }
    }
}
Python
def dfs(image, x, y, oldColor, newColor):
  
    # Check boundary conditions and color match
    if (x < 0 or x >= len(image) or y < 0 or 
        y >= len(image[0]) or image[x][y] != oldColor):
        return

    # Change the color
    image[x][y] = newColor

    # Visit all adjacent pixels
    dfs(image, x + 1, y, oldColor, newColor)
    dfs(image, x - 1, y, oldColor, newColor)
    dfs(image, x, y + 1, oldColor, newColor)
    dfs(image, x, y - 1, oldColor, newColor)

def floodFill(image, sr, sc, newColor):
  
    # If the starting pixel already has the new color
    if image[sr][sc] == newColor:
        return image

    # Call DFS with the starting pixel's original color
    dfs(image, sr, sc, image[sr][sc], newColor)

    return image

if __name__ == "__main__":
  
    # Input initialization
    image = [[1, 1, 1, 0],[0, 1, 1, 1],[1, 0, 1, 1]]
    sr, sc, newColor = 1, 2, 2

    # Perform flood fill
    result = floodFill(image, sr, sc, newColor)

    for row in result:
        print(" ".join(map(str, row)))
C#
// C# implementation of Flood Fill Algorithm using DFS
using System;

class GfG {

    // Helper method to perform DFS and fill connected pixels
    static void dfs(int[,] image, int x, int y, int oldColor, int newColor){
        
        // Base case: check if pixel is out of bounds or not
        // matching old color
        if (x < 0 || x >= image.GetLength(0) || 
            y < 0 || y >= image.GetLength(1) || 
            image[x, y] != oldColor) {
                
            return;
        }

        // Update the current pixel's color
        image[x, y] = newColor;

        // Recursively call DFS in all 4 directions (up, down, left, right)
        dfs(image, x + 1, y, oldColor, newColor); 
        dfs(image, x - 1, y, oldColor, newColor); 
        dfs(image, x, y + 1, oldColor, newColor); 
        dfs(image, x, y - 1, oldColor, newColor); 
    }

    // Main function to trigger the flood fill
    static int[,] floodFill(int[,] image, int sr, int sc, int newColor) {
        
        // If the pixel at (sr, sc) is already the new color, return as is
        if (image[sr, sc] == newColor) {
            return image;
        }

        // Call DFS from the starting pixel using its original color
        dfs(image, sr, sc, image[sr, sc], newColor);

        // Return the modified image
        return image;
    }

    // Driver code
    static void Main(string[] args) {
        
        // Example image (2D grid of pixels)
        int[,] image = {
            {1, 1, 1, 0},
            {0, 1, 1, 1},
            {1, 0, 1, 1}
        };

        // Starting coordinates (sr, sc) and new color to fill
        int sr = 1, sc = 2, newColor = 2;

        // Call flood fill algorithm
        int[,] result = floodFill(image, sr, sc, newColor);

        // Print the final filled image
        for (int i = 0; i < result.GetLength(0); i++) {
            
            for (int j = 0; j < result.GetLength(1); j++) {
                Console.Write(result[i, j] + " ");
            }
            
            // move to next line after each row
            Console.WriteLine(); 
        }
    }
}
JavaScript
function dfs(image, x, y, oldColor, newColor) {

    // Base case: Check if (x, y) is out of bounds OR pixel
    //  is not of the old color
    if ( x < 0 || x >= image.length || 
         y < 0 || y >= image[0].length || 
         image[x][y] !== oldColor) {
        // Backtrack if invalid
        return; 
    }

    // Change the color of the current pixel to newColor
    image[x][y] = newColor;

    // Recursively call DFS in all four directions
    dfs(image, x + 1, y, oldColor, newColor); 
    dfs(image, x - 1, y, oldColor, newColor); 
    dfs(image, x, y + 1, oldColor, newColor); 
    dfs(image, x, y - 1, oldColor, newColor); 
}

// Main function to trigger flood fill using DFS
function floodFill(image, sr, sc, newColor) {
    // Edge case: If the starting pixel already has 
    //the new color, no need to fill
    if (image[sr][sc] === newColor) {
        return image;
    }

    // Get the original color of the starting pixel
    const oldColor = image[sr][sc];

    // Start DFS from the given pixel
    dfs(image, sr, sc, oldColor, newColor);

    // Return the updated image
    return image;
}


// Sample input image (2D grid of pixels)
const image = [
    [1, 1, 1, 0],
    [0, 1, 1, 1],
    [1, 0, 1, 1]
];

// Starting coordinates (sr, sc) and the color to fill with
const sr = 1, sc = 2, newColor = 2;

// Perform flood fill
const result = floodFill(image, sr, sc, newColor);

// Print the result
result.forEach(row => {
        // Print each row as a space-separated string
        console.log(row.join(" ")); 
});

Output
2 2 2 0 
0 2 2 2 
1 0 2 2 

Time Complexity: O(m * n), where m and n are the dimensions of the image, as each pixel is visited once.
Space Complexity: O(m * n), due to the recursion stack in the worst case of all pixels being connected.

[Approach 2] Using Breadth-First Search – O(m * n) Time and O(m * n) Space

The idea is to use Breadth-First Search (BFS) to change all connected pixels with the original color (color of image[sr][sc]) to a new color (newColor). BFS uses a queue to explore all reachable pixels level by level (horizontally and vertically). For each pixel, it checks its adjacent pixels, and if they match the original color, it changes their color and adds them to the queue for further exploration. This process ensures that all connected pixels are filled with the new color.

The BFS approach would work better in general as it does not require overhead of recursion.

Step-by-Step Implementation :

  • Save the color of the starting pixel image[sr][sc] in a variable. This helps us identify which pixels need to be changed.
  • Use a queue (FIFO) to keep track of pixels that need to be processed. Start by adding the starting pixel (sr, sc) to the queue.
  • Start BFS traversl, While the queue is not empty, remove the front pixel, update its color to newColor, and check all four adjacent pixels, if they’re within bounds and match the original color, add them to the queue for further processing.
  • Repeat until the queue is empty, Continue the above process until all connected pixels with the original color have been visited and updated.
  • After the BFS traversal, return the updated image with the filled region.
C++
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

vector<vector<int>> floodFill(
    vector<vector<int>>& image, int sr, 
    int sc, int newColor) {

    // If the starting pixel already has the new color
    if (image[sr][sc] == newColor) {
        return image;
    }

    // Direction vectors for traversing 4 directions
    vector<pair<int, int>> directions = {
        {1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    
    // Initialize the queue for BFS
    queue<pair<int, int>> q;
    int oldColor = image[sr][sc];
    q.push({sr, sc});
    
    // Change the color of the starting pixel
    image[sr][sc] = newColor;

    // Perform BFS
    while (!q.empty()) {
        pair<int, int> front = q.front();
        int x = front.first, y = front.second;
        q.pop();
        
        // Traverse all 4 directions
        for (const pair<int, int>& direction : directions) {
            int nx = x + direction.first;
            int ny = y + direction.second;
            
            // Check boundary conditions and color match
            if (nx >= 0 && nx < image.size() && 
                ny >= 0 && ny < image[0].size() && 
                image[nx][ny] == oldColor) {
                
                // Change the color and enqueue
                image[nx][ny] = newColor;
                q.push({nx, ny});
            }
        }
    }

    return image;
}

int main() {
    
    // Define the input 2D image (grid of pixel colors)
    vector<vector<int>> image = {
        {1, 1, 1, 0},
        {0, 1, 1, 1},
        {1, 0, 1, 1}
    };

    // Starting pixel coordinates (row = 1, column = 2)
    int sr = 1, sc = 2;

    // New color to apply to the connected region
    int newColor = 2;

    // Call the floodFill function to perform DFS/BFS fill from the
    // starting pixel
    vector<vector<int>> result = floodFill(image, sr, sc, newColor);

    // Print the updated image after flood fill
    for (auto& row : result) {
        for (auto& pixel : row) {
            
            // Print each pixel with a space
            cout << pixel << " ";  
        }
        
        // Move to the next line after printing each row
        cout << "\n";  
    }
    
    return 0; 
}
Java
// Java implementation of Flood Fill Algorithm
// using BFS
import java.util.*;

class GfG {

    // Directions for traversing in 4-neighbor cells
    private static final int[][] directions = {
        {1, 0}, {-1, 0}, {0, 1}, {0, -1}
    };

    public static int[][] floodFill(int[][] image,
                                    int sr, int sc, 
                                    int newColor) {

        // If the starting pixel already has the new color
        if (image[sr][sc] == newColor) {
            return image;
        }

        int oldColor = image[sr][sc];
        Queue<int[]> q = new LinkedList<>();
        q.offer(new int[]{sr, sc});

        // Change the color of the starting pixel
        image[sr][sc] = newColor;

        while (!q.isEmpty()) {
            int[] front = q.poll();
            int x = front[0], y = front[1];

            for (int[] direction : directions) {
                int nx = x + direction[0];
                int ny = y + direction[1];

                // Check boundary conditions and color match
                if (nx >= 0 && nx < image.length && 
                    ny >= 0 && ny < image[0].length && 
                    image[nx][ny] == oldColor) {

                    // Change the color and enqueue
                    image[nx][ny] = newColor;
                    q.offer(new int[]{nx, ny});
                }
            }
        }

        return image;
    }

    public static void main(String[] args) {

    // Define the input 2D image as a matrix where 
    // each element represents a pixel's color
    int[][] image = {
        {1, 1, 1, 0},
        {0, 1, 1, 1},
        {1, 0, 1, 1}
    };

    // sr: starting row index, sc: starting column 
    // index for the flood fill
    int sr = 1, sc = 2;

    // newColor: the color that we want to fill the 
    // connected component with
    int newColor = 2;

    // Call the floodFill function to apply the 
    // newColor starting from (sr, sc)
    int[][] result = floodFill(image, sr, sc, newColor);

    // Print the updated image after flood fill
    for (int[] row : result) {         
        for (int pixel : row) {       
            System.out.print(pixel + " ");  
        }
        // Move to the next line after each row
        System.out.println();        
    }
    
}

}
Python
from collections import deque 

# Function to perform flood fill using BFS
def floodFill(image, sr, sc, newColor):
    rows, cols = len(image), len(image[0]) 
    
    # Store the color at the starting pixel
    oldColor = image[sr][sc]  
    
    # Return the image if the starting pixel 
    # already has the new color
    if oldColor == newColor:
        return image  

    # Create a queue to manage the BFS traversal
    q = deque([(sr, sc)])  
    
    # Directions to explore: down, up, right, left
    directions = [(1, 0), (-1, 0), (0, 1), (0, -1)]  

    # Change the color of the starting pixel
    image[sr][sc] = newColor  
    
    # BFS traversal
    while q:  
        x, y = q.popleft()  
        
        # Explore all four possible directions
        for dx, dy in directions:
            nx, ny = x + dx, y + dy

            # Check if new coordinates are within bounds 
            # and have the old color
            if 0 <= nx < rows and 0 <= ny < cols \
                         and image[nx][ny] == oldColor:
              
                # Change the color and add the pixel to 
                # queue for further exploration
                image[nx][ny] = newColor
                q.append((nx, ny))

    return image  
    
if __name__ == "__main__":

    # Input 2D image represented as a grid of pixels 
    # (each with an integer color)
    image = [
        [1, 1, 1, 0],
        [0, 1, 1, 1],
        [1, 0, 1, 1]
    ]

    # Starting pixel coordinates (sr, sc) and the new color to apply
    sr, sc, newColor = 1, 2, 2 

    # Perform the flood fill operation
    result = floodFill(image, sr, sc, newColor)

    # Print the updated image row by row
    for row in result:  
        # Convert each row's integers to strings and join them with spaces
        print(" ".join(map(str, row)))
C#
using System;
using System.Collections.Generic;

class GfG {

    // BFS-based Flood Fill implementation
    static int[,] floodFill(int[,] image, 
                                   int sr, int sc, 
                                   int newColor) {
        
        // Get the original color of the starting pixel
        int oldColor = image[sr, sc];
        
        // If the starting pixel already has the new 
        // color, return the image
        if (oldColor == newColor) {
            return image;
        }

        // Dimensions of the image
        int rows = image.GetLength(0);
        int cols = image.GetLength(1);

        // Queue for BFS
        Queue<(int, int)> q = new Queue<(int, int)>();

        // Add the starting pixel to the queue
        q.Enqueue((sr, sc));

        // Change the starting pixel color
        image[sr, sc] = newColor;

        // Direction vectors for adjacent pixels
        int[] dx = { -1, 1, 0, 0 };
        int[] dy = { 0, 0, -1, 1 };

        // BFS loop
        while (q.Count > 0) {
            (int x, int y) = q.Dequeue();

            // Traverse all 4 directions
            for (int i = 0; i < 4; i++) {
                int nx = x + dx[i];
                int ny = y + dy[i];

                // Check boundary conditions and color match
                if (nx >= 0 && nx < rows && ny >= 0 
                            && ny < cols
                            && image[nx, ny] == oldColor) {
                  
                    // Change the color
                    image[nx, ny] = newColor;

                    // Add the pixel to the queue
                    q.Enqueue((nx, ny));
                }
            }
        }

        return image;
    }

    static void Main(string[] args) {

    // Define a 2D array (matrix) representing the image where 
    // each element is a pixel color
    int[,] image = {
        {1, 1, 1, 0},
        {0, 1, 1, 1},
        {1, 0, 1, 1}
    };

    // sr: starting row, sc: starting column, newColor: the color to apply
    int sr = 1, sc = 2, newColor = 2;

    // Call the floodFill function to apply the new color to 
    // connected pixels
    int[,] result = floodFill(image, sr, sc, newColor);

    // Print the updated image
    for (int i = 0; i < result.GetLength(0); i++) {            
        for (int j = 0; j < result.GetLength(1); j++) {        
            Console.Write(result[i, j] + " ");                 
        }
        Console.WriteLine();                                  
    }
}

}
JavaScript
function floodFill(image, sr, sc, newColor) {
    const oldColor = image[sr][sc];
    
    // If the starting pixel already has the new color, return
    if (oldColor === newColor) {
        return image;
    }

    // Dimensions of the image
    const rows = image.length;
    const cols = image[0].length;

    // Queue for BFS
    const q = [[sr, sc]];

    // Change the starting pixel's color
    image[sr][sc] = newColor;

    // Direction vectors for 4 adjacent directions
    const directions = [ [1, 0], [-1, 0], [0, 1], [0, -1] ];

    // BFS loop
    while (q.length > 0) {
        const [x, y] = q.shift();

        for (const [dx, dy] of directions) {
            const nx = x + dx;
            const ny = y + dy;

            // Check boundary conditions and color match
            if (
                nx >= 0 && nx < rows && 
                ny >= 0 && ny < cols && 
                image[nx][ny] === oldColor
            ) {
                // Change color and add to queue
                image[nx][ny] = newColor;
                q.push([nx, ny]);
            }
        }
    }

    return image;
}

// Define a 2D array (image) where each element represents a pixel's color
const image = [
    [1, 1, 1, 0],
    [0, 1, 1, 1],
    [1, 0, 1, 1]
];

// sr: starting row, sc: starting column, newColor: the color to fill
const sr = 1, sc = 2, newColor = 2;

// Call the floodFill function to update the image with the new color
const result = floodFill(image, sr, sc, newColor);

// Print the updated image row by row
result.forEach(row => {
    // Join each row's elements with a space and print the row
    console.log(row.join(" "));
});

Output
2 2 2 0 
0 2 2 2 
1 0 2 2 

Time Complexity: O(m * n),as all pixels are visited once in bfs.
Space Complexity: O(m * n), because the queue can hold all pixels in the worst-case scenario.



Next Article

Similar Reads