Flood Fill Algorithm
Given a 2D screen arr[][] where each arr[i][j] is an integer representing the color of that pixel, also given the location of a pixel (X, Y) and a color C, the task is to replace the color of the given pixel and all the adjacent same-colored pixels with the given color.
Example:
Input: arr[][] = {
{1, 1, 1, 1, 1, 1, 1, 1},
{1, 1, 1, 1, 1, 1, 0, 0},
{1, 0, 0, 1, 1, 0, 1, 1},
{1, 2, 2, 2, 2, 0, 1, 0},
{1, 1, 1, 2, 2, 0, 1, 0},
{1, 1, 1, 2, 2, 2, 2, 0},
{1, 1, 1, 1, 1, 2, 1, 1},
{1, 1, 1, 1, 1, 2, 2, 1}}
X = 4, Y = 4, C = 3
Output:
1 1 1 1 1 1 1 1
1 1 1 1 1 1 0 0
1 0 0 1 1 0 1 1
1 3 3 3 3 0 1 0
1 1 1 3 3 0 1 0
1 1 1 3 3 3 3 0
1 1 1 1 1 3 1 1
1 1 1 1 1 3 3 1
Explanation:
The values in the given 2D screen indicate colors of the pixels. X and Y are coordinates of the brush, C is the color that should replace the previous color on screen[X][Y] and all surrounding pixels with the same color. Hence all the 2 are replaced with 3.
BFS Approach: The idea is to use BFS traversal to replace the color with the new color.
- Create an empty queue lets say Q.
- Push the starting location of the pixel as given in the input and apply 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 into the queue if valid (had not been colored with replacement color and have the same color as the old color).
Below is the implementation of the above approach:
C++
// C++ implementation of the approach #include <bits/stdc++.h> using namespace std; // Function that returns true if // the given pixel is valid bool isValid( int screen[][8], int m, int n, int x, int y, int prevC, int newC) { if (x < 0 || x >= m || y < 0 || y >= n || screen[x][y] != prevC || screen[x][y]== newC) return false ; return true ; } // FloodFill function void floodFill( int screen[][8], int m, int n, int x, int y, int prevC, int newC) { vector<pair< int , int >> queue; // Append the position of starting // pixel of the component pair< int , int > p(x,y); queue.push_back(p); // Color the pixel with the new color screen[x][y] = newC; // While the queue is not empty i.e. the // whole component having prevC color // is not colored with newC color while (queue.size() > 0) { // Dequeue the front node pair< int , int > currPixel = queue[queue.size() - 1]; queue.pop_back(); int posX = currPixel.first; int posY = currPixel.second; // Check if the adjacent // pixels are valid if (isValid(screen, m, n, posX + 1, posY, prevC, newC)) { // Color with newC // if valid and enqueue screen[posX + 1][posY] = newC; p.first = posX + 1; p.second = posY; queue.push_back(p); } if (isValid(screen, m, n, posX-1, posY, prevC, newC)) { screen[posX-1][posY]= newC; p.first = posX-1; p.second = posY; queue.push_back(p); } if (isValid(screen, m, n, posX, posY + 1, prevC, newC)) { screen[posX][posY + 1]= newC; p.first = posX; p.second = posY + 1; queue.push_back(p); } if (isValid(screen, m, n, posX, posY-1, prevC, newC)) { screen[posX][posY-1]= newC; p.first = posX; p.second = posY-1; queue.push_back(p); } } } int main() { int screen[][8] ={ {1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 0, 0}, {1, 0, 0, 1, 1, 0, 1, 1}, {1, 2, 2, 2, 2, 0, 1, 0}, {1, 1, 1, 2, 2, 0, 1, 0}, {1, 1, 1, 2, 2, 2, 2, 0}, {1, 1, 1, 1, 1, 2, 1, 1}, {1, 1, 1, 1, 1, 2, 2, 1}}; // Row of the display int m = 8; // Column of the display int n = 8; // Co-ordinate provided by the user int x = 4; int y = 4; // Current color at that co-ordinate int prevC = screen[x][y]; // New color that has to be filled int newC = 3; floodFill(screen, m, n, x, y, prevC, newC); // Printing the updated screen for ( int i = 0; i < m; i++) { for ( int j = 0; j < n; j++) { cout << screen[i][j] << " " ; } cout << endl; } return 0; } // This code is contributed by suresh07. |
Java
// Java implementation of the approach import java.util.*; import java.awt.Point; public class Main { // Function that returns true if // the given pixel is valid static boolean isValid( int [][] screen, int m, int n, int x, int y, int prevC, int newC) { if (x < 0 || x >= m || y < 0 || y >= n || screen[x][y] != prevC || screen[x][y]== newC) return false ; return true ; } // FloodFill function static void floodFill( int [][] screen, int m, int n, int x, int y, int prevC, int newC) { Vector<Point> queue = new Vector<Point>(); // Append the position of starting // pixel of the component queue.add( new Point(x, y)); // Color the pixel with the new color screen[x][y] = newC; // While the queue is not empty i.e. the // whole component having prevC color // is not colored with newC color while (queue.size() > 0 ) { // Dequeue the front node Point currPixel = queue.get(queue.size() - 1 ); queue.remove(queue.size() - 1 ); int posX = currPixel.x; int posY = currPixel.y; // Check if the adjacent // pixels are valid if (isValid(screen, m, n, posX + 1 , posY, prevC, newC)) { // Color with newC // if valid and enqueue screen[posX + 1 ][posY] = newC; queue.add( new Point(posX + 1 , posY)); } if (isValid(screen, m, n, posX- 1 , posY, prevC, newC)) { screen[posX- 1 ][posY]= newC; queue.add( new Point(posX- 1 , posY)); } if (isValid(screen, m, n, posX, posY + 1 , prevC, newC)) { screen[posX][posY + 1 ]= newC; queue.add( new Point(posX, posY + 1 )); } if (isValid(screen, m, n, posX, posY- 1 , prevC, newC)) { screen[posX][posY- 1 ]= newC; queue.add( new Point(posX, posY- 1 )); } } } public static void main(String[] args) { int [][] screen ={ { 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 }, { 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 }, { 1 , 0 , 0 , 1 , 1 , 0 , 1 , 1 }, { 1 , 2 , 2 , 2 , 2 , 0 , 1 , 0 }, { 1 , 1 , 1 , 2 , 2 , 0 , 1 , 0 }, { 1 , 1 , 1 , 2 , 2 , 2 , 2 , 0 }, { 1 , 1 , 1 , 1 , 1 , 2 , 1 , 1 }, { 1 , 1 , 1 , 1 , 1 , 2 , 2 , 1 }}; // Row of the display int m = screen.length; // Column of the display int n = screen.length; // Co-ordinate provided by the user int x = 4 ; int y = 4 ; // Current color at that co-ordinate int prevC = screen[x][y]; // New color that has to be filled int newC = 3 ; floodFill(screen, m, n, x, y, prevC, newC); // Printing the updated screen for ( int i = 0 ; i < m; i++) { for ( int j = 0 ; j < n; j++) { System.out.print(screen[i][j] + " " ); } System.out.println(); } } } // This code is contributed by mukesh07. |
Python3
# Python3 implementation of the approach # Function that returns true if # the given pixel is valid def isValid(screen, m, n, x, y, prevC, newC): if x< 0 or x> = m\ or y< 0 or y> = n or \ screen[x][y]! = prevC\ or screen[x][y] = = newC: return False return True # FloodFill function def floodFill(screen, m, n, x, y, prevC, newC): queue = [] # Append the position of starting # pixel of the component queue.append([x, y]) # Color the pixel with the new color screen[x][y] = newC # While the queue is not empty i.e. the # whole component having prevC color # is not colored with newC color while queue: # Dequeue the front node currPixel = queue.pop() posX = currPixel[ 0 ] posY = currPixel[ 1 ] # Check if the adjacent # pixels are valid if isValid(screen, m, n, posX + 1 , posY, prevC, newC): # Color with newC # if valid and enqueue screen[posX + 1 ][posY] = newC queue.append([posX + 1 , posY]) if isValid(screen, m, n, posX - 1 , posY, prevC, newC): screen[posX - 1 ][posY] = newC queue.append([posX - 1 , posY]) if isValid(screen, m, n, posX, posY + 1 , prevC, newC): screen[posX][posY + 1 ] = newC queue.append([posX, posY + 1 ]) if isValid(screen, m, n, posX, posY - 1 , prevC, newC): screen[posX][posY - 1 ] = newC queue.append([posX, posY - 1 ]) # Driver code screen = [ [ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ], [ 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 ], [ 1 , 0 , 0 , 1 , 1 , 0 , 1 , 1 ], [ 1 , 2 , 2 , 2 , 2 , 0 , 1 , 0 ], [ 1 , 1 , 1 , 2 , 2 , 0 , 1 , 0 ], [ 1 , 1 , 1 , 2 , 2 , 2 , 2 , 0 ], [ 1 , 1 , 1 , 1 , 1 , 2 , 1 , 1 ], [ 1 , 1 , 1 , 1 , 1 , 2 , 2 , 1 ], ] # Row of the display m = len (screen) # Column of the display n = len (screen[ 0 ]) # Co-ordinate provided by the user x = 4 y = 4 # Current color at that co-ordinate prevC = screen[x][y] # New color that has to be filled newC = 3 floodFill(screen, m, n, x, y, prevC, newC) # Printing the updated screen for i in range (m): for j in range (n): print (screen[i][j], end = ' ' ) print () |
C#
// C# implementation of the approach using System; using System.Collections.Generic; class GFG { // Function that returns true if // the given pixel is valid static bool isValid( int [,] screen, int m, int n, int x, int y, int prevC, int newC) { if (x < 0 || x >= m || y < 0 || y >= n || screen[x, y] != prevC || screen[x,y]== newC) return false ; return true ; } // FloodFill function static void floodFill( int [,] screen, int m, int n, int x, int y, int prevC, int newC) { List<Tuple< int , int >> queue = new List<Tuple< int , int >>(); // Append the position of starting // pixel of the component queue.Add( new Tuple< int , int >(x, y)); // Color the pixel with the new color screen[x,y] = newC; // While the queue is not empty i.e. the // whole component having prevC color // is not colored with newC color while (queue.Count > 0) { // Dequeue the front node Tuple< int , int > currPixel = queue[queue.Count - 1]; queue.RemoveAt(queue.Count - 1); int posX = currPixel.Item1; int posY = currPixel.Item2; // Check if the adjacent // pixels are valid if (isValid(screen, m, n, posX + 1, posY, prevC, newC)) { // Color with newC // if valid and enqueue screen[posX + 1,posY] = newC; queue.Add( new Tuple< int , int >(posX + 1, posY)); } if (isValid(screen, m, n, posX-1, posY, prevC, newC)) { screen[posX-1,posY]= newC; queue.Add( new Tuple< int , int >(posX-1, posY)); } if (isValid(screen, m, n, posX, posY + 1, prevC, newC)) { screen[posX,posY + 1]= newC; queue.Add( new Tuple< int , int >(posX, posY + 1)); } if (isValid(screen, m, n, posX, posY-1, prevC, newC)) { screen[posX,posY-1]= newC; queue.Add( new Tuple< int , int >(posX, posY-1)); } } } static void Main() { int [,] screen ={ {1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 0, 0}, {1, 0, 0, 1, 1, 0, 1, 1}, {1, 2, 2, 2, 2, 0, 1, 0}, {1, 1, 1, 2, 2, 0, 1, 0}, {1, 1, 1, 2, 2, 2, 2, 0}, {1, 1, 1, 1, 1, 2, 1, 1}, {1, 1, 1, 1, 1, 2, 2, 1}}; // Row of the display int m = screen.GetLength(0); // Column of the display int n = screen.GetLength(1); // Co-ordinate provided by the user int x = 4; int y = 4; // Current color at that co-ordinate int prevC = screen[x,y]; // New color that has to be filled int newC = 3; floodFill(screen, m, n, x, y, prevC, newC); // Printing the updated screen for ( int i = 0; i < m; i++) { for ( int j = 0; j < n; j++) { Console.Write(screen[i,j] + " " ); } Console.WriteLine(); } } } // This code is contributed by divyeshrabadiya07. |
Javascript
<script> // Javascript implementation of the approach // Function that returns true if // the given pixel is valid function isValid(screen, m, n, x, y, prevC, newC) { if (x<0 || x>= m || y<0 || y>= n || screen[x][y]!= prevC || screen[x][y]== newC) return false ; return true ; } // FloodFill function function floodFill(screen, m, n, x, y, prevC, newC) { let queue = []; // Append the position of starting // pixel of the component queue.push([x, y]); // Color the pixel with the new color screen[x][y] = newC; // While the queue is not empty i.e. the // whole component having prevC color // is not colored with newC color while (queue.length > 0) { // Dequeue the front node currPixel = queue[queue.length - 1]; queue.pop(); let posX = currPixel[0]; let posY = currPixel[1]; // Check if the adjacent // pixels are valid if (isValid(screen, m, n, posX + 1, posY, prevC, newC)) { // Color with newC // if valid and enqueue screen[posX + 1][posY] = newC; queue.push([posX + 1, posY]); } if (isValid(screen, m, n, posX-1, posY, prevC, newC)) { screen[posX-1][posY]= newC; queue.push([posX-1, posY]); } if (isValid(screen, m, n, posX, posY + 1, prevC, newC)) { screen[posX][posY + 1]= newC; queue.push([posX, posY + 1]); } if (isValid(screen, m, n, posX, posY-1, prevC, newC)) { screen[posX][posY-1]= newC; queue.push([posX, posY-1]); } } } let screen =[ [1, 1, 1, 1, 1, 1, 1, 1], [1, 1, 1, 1, 1, 1, 0, 0], [1, 0, 0, 1, 1, 0, 1, 1], [1, 2, 2, 2, 2, 0, 1, 0], [1, 1, 1, 2, 2, 0, 1, 0], [1, 1, 1, 2, 2, 2, 2, 0], [1, 1, 1, 1, 1, 2, 1, 1], [1, 1, 1, 1, 1, 2, 2, 1]]; // Row of the display let m = screen.length; // Column of the display let n = screen[0].length; // Co-ordinate provided by the user let x = 4; let y = 4; // Current color at that co-ordinate let prevC = screen[x][y]; // New color that has to be filled let newC = 3; floodFill(screen, m, n, x, y, prevC, newC); // Printing the updated screen for (let i = 0; i < m; i++) { for (let j = 0; j < n; j++) { document.write(screen[i][j] + " " ); } document.write( "</br>" ); } // This code is contributed by divyesh072019. </script> |
1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 0 0 1 1 0 1 1 1 3 3 3 3 0 1 0 1 1 1 3 3 0 1 0 1 1 1 3 3 3 3 0 1 1 1 1 1 3 1 1 1 1 1 1 1 3 3 1
Time Complexity: O(N*M)
Auxiliary Space: O(N*M)
An Approach using DFS:
- Change the color of source row and source column with given color
- Do dfs in four direction
Below is the implementation of the above approach:
C++
// C++ implementation of the approach #include <bits/stdc++.h> using namespace std; // Floodfill function void floodFill(vector<vector< int > >& screen, int sr, int sc, int row, int col, int source, int color) { // Condition for checking out of bounds if (sr < 0 || sr >= row || sc < 0 || sc >= col) return ; if (screen[sr][sc] != source) return ; screen[sr][sc] = color; floodFill(screen, sr - 1, sc, row, col, source, color); // left floodFill(screen, sr + 1, sc, row, col, source, color); // right floodFill(screen, sr, sc + 1, row, col, source, color); // top floodFill(screen, sr, sc - 1, row, col, source, color); // bottom } // Driver code int main() { vector<vector< int > > screen = { { 1, 1, 1, 1, 1, 1, 1, 1 }, { 1, 1, 1, 1, 1, 1, 0, 0 }, { 1, 0, 0, 1, 1, 0, 1, 1 }, { 1, 2, 2, 2, 2, 0, 1, 0 }, { 1, 1, 1, 2, 2, 0, 1, 0 }, { 1, 1, 1, 2, 2, 2, 2, 0 }, { 1, 1, 1, 1, 1, 2, 1, 1 }, { 1, 1, 1, 1, 1, 2, 2, 1 } }; // Row of the display int m = 8; // Column of the display int n = 8; // Co-ordinate provided by the user int x = 4; int y = 4; // Current color at that co-ordinate int prevC = screen[x][y]; // New color that has to be filled int newC = 3; floodFill(screen, x, y, m, n, prevC, newC); // Printing the updated screen for ( int i = 0; i < m; i++) { for ( int j = 0; j < n; j++) { cout << screen[i][j] << " " ; } cout << endl; } return 0; } // This code is contributed by hkdass001. |
Java
import java.util.ArrayList; public class FloodFill { // Floodfill function public static void floodFill( int [][] screen, int sr, int sc, int row, int col, int source, int color) { // Condition for checking out of bounds if (sr < 0 || sr >= row || sc < 0 || sc >= col) return ; if (screen[sr][sc] != source) return ; screen[sr][sc] = color; floodFill(screen, sr - 1 , sc, row, col, source, color); // left floodFill(screen, sr + 1 , sc, row, col, source, color); // right floodFill(screen, sr, sc + 1 , row, col, source, color); // top floodFill(screen, sr, sc - 1 , row, col, source, color); // bottom } public static void main(String[] args) { int [][] screen = {{ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 }, { 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 }, { 1 , 0 , 0 , 1 , 1 , 0 , 1 , 1 }, { 1 , 2 , 2 , 2 , 2 , 0 , 1 , 0 }, { 1 , 1 , 1 , 2 , 2 , 0 , 1 , 0 }, { 1 , 1 , 1 , 2 , 2 , 2 , 2 , 0 }, { 1 , 1 , 1 , 1 , 1 , 2 , 1 , 1 }, { 1 , 1 , 1 , 1 , 1 , 2 , 2 , 1 }}; // Row of the display int m = 8 ; // Column of the display int n = 8 ; // Co-ordinate provided by the user int x = 4 ; int y = 4 ; // Current color at that co-ordinate int prevC = screen[x][y]; // New color that has to be filled int newC = 3 ; floodFill(screen, x, y, m, n, prevC, newC); // Printing the updated screen for ( int i = 0 ; i < m; i++) { for ( int j = 0 ; j < n; j++) { System.out.print(screen[i][j] + " " ); } System.out.println(); } } } |
Python3
from typing import List , Tuple def flood_fill(screen: List [ List [ int ]], sr: int , sc: int , row: int , col: int , source: int , color: int ) - > None : # Condition for checking out of bounds if sr < 0 or sr > = row or sc < 0 or sc > = col: return if screen[sr][sc] ! = source: return screen[sr][sc] = color flood_fill(screen, sr - 1 , sc, row, col, source, color) # left flood_fill(screen, sr + 1 , sc, row, col, source, color) # right flood_fill(screen, sr, sc + 1 , row, col, source, color) # top flood_fill(screen, sr, sc - 1 , row, col, source, color) # bottom if __name__ = = "__main__" : screen = [ [ 1 , 1 , 1 , 1 , 1 , 1 , 1 , 1 ], [ 1 , 1 , 1 , 1 , 1 , 1 , 0 , 0 ], [ 1 , 0 , 0 , 1 , 1 , 0 , 1 , 1 ], [ 1 , 2 , 2 , 2 , 2 , 0 , 1 , 0 ], [ 1 , 1 , 1 , 2 , 2 , 0 , 1 , 0 ], [ 1 , 1 , 1 , 2 , 2 , 2 , 2 , 0 ], [ 1 , 1 , 1 , 1 , 1 , 2 , 1 , 1 ], [ 1 , 1 , 1 , 1 , 1 , 2 , 2 , 1 ] ] # Row of the display m = 8 # Column of the display n = 8 # Coordinate provided by the user x = 4 y = 4 # Current color at that coordinate prevC = screen[x][y] # New color that has to be filled newC = 3 flood_fill(screen, x, y, m, n, prevC, newC) # Printing the updated screen for i in range (m): for j in range (n): print (screen[i][j], end = " " ) print () |
Javascript
// JavaScript implementation of the approach // Floodfill function function floodFill(screen, sr, sc, row, col, source, color) { // Condition for checking out of bounds if (sr < 0 || sr >= row || sc < 0 || sc >= col) return ; if (screen[sr][sc] != source) return ; screen[sr][sc] = color; floodFill(screen, sr - 1, sc, row, col, source, color); // left floodFill(screen, sr + 1, sc, row, col, source, color); // right floodFill(screen, sr, sc + 1, row, col, source, color); // top floodFill(screen, sr, sc - 1, row, col, source, color); // bottom } // Driver code let screen = [ [ 1, 1, 1, 1, 1, 1, 1, 1 ], [ 1, 1, 1, 1, 1, 1, 0, 0 ], [ 1, 0, 0, 1, 1, 0, 1, 1 ], [ 1, 2, 2, 2, 2, 0, 1, 0 ], [ 1, 1, 1, 2, 2, 0, 1, 0 ], [ 1, 1, 1, 2, 2, 2, 2, 0 ], [ 1, 1, 1, 1, 1, 2, 1, 1 ], [ 1, 1, 1, 1, 1, 2, 2, 1 ] ]; // Row of the display let m = 8; // Column of the display let n = 8; // Co-ordinate provided by the user let x = 4; let y = 4; // Current color at that co-ordinate let prevC = screen[x][y]; // New color that has to be filled let newC = 3; floodFill(screen, x, y, m, n, prevC, newC); // Printing the updated screen for (let i = 0; i < m; i++) { let temp = "" ; for (let j = 0; j < n; j++) { document.write(screen[i][j] + " " ); } document.write( "</br>" ); } // This code is contributed by Gautam goel |
C#
using System; namespace FloodFill { class Program { static void Main( string [] args) { int [,] screen = { {1, 1, 1, 1, 1, 1, 1, 1}, {1, 1, 1, 1, 1, 1, 0, 0}, {1, 0, 0, 1, 1, 0, 1, 1}, {1, 2, 2, 2, 2, 0, 1, 0}, {1, 1, 1, 2, 2, 0, 1, 0}, {1, 1, 1, 2, 2, 2, 2, 0}, {1, 1, 1, 1, 1, 2, 1, 1}, {1, 1, 1, 1, 1, 2, 2, 1} }; // Dimensions of the screen int m = 8; int n = 8; // Coordinates provided by the user int x = 4; int y = 4; // Current color at the given coordinate int prevC = screen[x, y]; // New color to fill int newC = 3; FloodFill(screen, x, y, m, n, prevC, newC); // Printing the updated screen for ( int i = 0; i < m; i++) { for ( int j = 0; j < n; j++) { Console.Write(screen[i, j] + " " ); } Console.WriteLine(); } Console.ReadKey(); } // Flood fill function static void FloodFill( int [,] screen, int sr, int sc, int row, int col, int source, int color) { // Check for out of bounds if (sr < 0 || sr >= row || sc < 0 || sc >= col) return ; // Check if the current pixel is not equal to the source color if (screen[sr, sc] != source) return ; screen[sr, sc] = color; // Recursively fill the surrounding pixels FloodFill(screen, sr - 1, sc, row, col, source, color); // left FloodFill(screen, sr + 1, sc, row, col, source, color); // right FloodFill(screen, sr, sc + 1, row, col, source, color); // top FloodFill(screen, sr, sc - 1, row, col, source, color); // bottom } } } |
1 1 1 1 1 1 1 1 1 1 1 1 1 1 0 0 1 0 0 1 1 0 1 1 1 3 3 3 3 0 1 0 1 1 1 3 3 0 1 0 1 1 1 3 3 3 3 0 1 1 1 1 1 3 1 1 1 1 1 1 1 3 3 1
Time Complexity: O(m*n)
Auxiliary Space: O(m + n), due to the recursive call stack.
Please Login to comment...