An image is represented by a 2-D array of integers, each integer representing the pixel value of the image. Given a coordinate (sr, sc) representing the starting pixel (row and column) of the flood fill, and a pixel value newColor, "flood fill" the image.
To perform a flood fill, consider the starting pixel, plus any pixels connected 4-directionally to the starting pixel of the same colour as the starting pixel, plus any pixels connected 4-directionally to those pixels (also with the same colour as the starting pixel), and so on. Replace the colour of all of the aforementioned pixels with the newColor.
Input: image = [ [1, 1, 1], [1, 1, 0], [1, 0, 1] ], sr = 1, sc = 1, newColor = 2
Output: [ [2, 2, 2], [2, 2, 0], [2, 0, 1] ]
Explanation: From the center of the image with position (sr, sc) = (1, 1) (i.e., the red pixel), all pixels connected by a path of the same color as the starting pixel (i.e., the blue pixels) are colored with the new color.
Note the bottom corner is not colored 2, because it is not 4-directionally connected to the starting pixel.
Input: image = [ [0, 1, 0], [1, 1, 0], [0, 0, 1] ], sr = 2, sc = 2, newColor = 3
Output: [ [0, 1, 0], [1, 1, 0], [0, 0, 3] ]
Explanation: Starting from the pixel at position (2, 2) (i.e., the blue pixel), we flood fill all adjacent pixels that have the same color as the starting pixel. In this case, only the pixel at position (2, 2) itself is of the same color. So, only that pixel gets colored with the new color, resulting in the updated image.
Input: image = [ [1, 1, 1], [1, 1, 0], [1, 0, 1] ], sr = 1, sc = 1, newColor = 0
· n == image.length
· m == image[i].length
· 1 <= m, n <= 50
· 0 <= image[i][j], color < 216
· 0 <= sr < n
· 0 <= sc < m
How to solve this problem using a graph?
Think of all the pixels in the image as nodes or vertices which are connected through each other via 4 edges.
Given the starting pixel, any traversal algorithm can be used to find all the neighbors having similar pixel value. During the traversal, each pixel value can be changed to the new color value to get the flood filled image.
How to traverse the neighbours efficiently?
The 4 neighbours of the current cell can be shown like this:
For efficient traversal of all neighboring pixels, the delRow and delCol arrays can be used where:
delRow = {-1, 0, 1, 0}
delCol = {0, 1, 0, -1}
#include <bits/stdc++.h>
using namespace std;
class Solution {
private:
// DelRow and delCol for neighbors
vector<int> delRow = {-1, 0, 1, 0};
vector<int> delCol = {0, 1, 0, -1};
/* Helper Function to check if a
pixel is within boundaries */
bool isValid(int &i, int &j,
int &n, int &m) {
// Return false if pixel is invalid
if(i < 0 || i >= n) return false;
if(j < 0 || j >= m) return false;
// Return true if pixel is valid
return true;
}
// Function to perform DFS traversal
void dfs(int row, int col, vector<vector<int>>&ans,
vector<vector<int>>& image, int newColor,
int iniColor) {
// color with new color
ans[row][col] = newColor;
// Getting the dimensions of image
int n = image.size();
int m = image[0].size();
// Traverse the 4 neighbors
for(int i=0; i < 4; i++) {
// Coordinates of new pixel
int nrow = row + delRow[i];
int ncol = col + delCol[i];
/* check for valid, unvisited pixels
having same initial color */
if(isValid(nrow, ncol, n, m) &&
image[nrow][ncol] == iniColor
&& ans[nrow][ncol] != newColor) {
// Recirsively perform DFS
dfs(nrow, ncol, ans, image,
newColor, iniColor);
}
}
}
public:
// Function to perform flood fill algorithm
vector<vector<int>> floodFill(vector<vector<int>> &image,
int sr, int sc, int newColor) {
// Store initial color
int iniColor = image[sr][sc];
// To store the updated image
vector<vector<int>> ans = image;
// Start DFS traversal from start cell
dfs(sr, sc, ans, image, newColor, iniColor);
// Return the answer image
return ans;
}
};
int main() {
vector<vector<int>> image = {
{1,1,1},
{1,1,0},
{1,0,1}
};
int sr = 1, sc = 1;
int newColor = 2;
int n = image.size();
int m = image[0].size();
/* Creating an instance of
Solution class */
Solution sol;
/* Function call to find the
number of islands in given grid*/
vector<vector<int>> ans = sol.floodFill(image, sr, sc, newColor);
cout << "Image after performing flood fill algorithm: \n\n";
for(int i=0; i < n; i++) {
for(int j=0; j < m; j++) {
cout << ans[i][j] << " ";
}
cout << endl;
}
return 0;
}
import java.util.*;
class Solution {
// DelRow and delCol for neighbors
private int[] delRow = {-1, 0, 1, 0};
private int[] delCol = {0, 1, 0, -1};
/* Helper Function to check if a
pixel is within boundaries */
private boolean isValid(int i, int j,
int n, int m) {
// Return false if pixel is invalid
if (i < 0 || i >= n) return false;
if (j < 0 || j >= m) return false;
// Return true if pixel is valid
return true;
}
// Function to perform DFS traversal
private void dfs(int row, int col, int[][] ans,
int[][] image, int newColor,
int iniColor) {
// color with new color
ans[row][col] = newColor;
// Getting the dimensions of image
int n = image.length;
int m = image[0].length;
// Traverse the 4 neighbors
for (int i = 0; i < 4; i++) {
// Coordinates of new pixel
int nrow = row + delRow[i];
int ncol = col + delCol[i];
// check for valid, unvisited pixels
// having same initial color
if (isValid(nrow, ncol, n, m) &&
image[nrow][ncol] == iniColor &&
ans[nrow][ncol] != newColor) {
// Recursively perform DFS
dfs(nrow, ncol, ans, image,
newColor, iniColor);
}
}
}
public int[][] floodFill(int[][] image, int sr,
int sc, int newColor) {
// Store initial color
int iniColor = image[sr][sc];
// To store the updated image
int[][] ans = new int[image.length][image[0].length];
for (int i = 0; i < image.length; i++) {
ans[i] = Arrays.copyOf(image[i], image[i].length);
}
// Start DFS traversal from start cell
dfs(sr, sc, ans, image, newColor, iniColor);
// Return the answer image
return ans;
}
public static void main(String[] args) {
int[][] image = {
{1, 1, 1},
{1, 1, 0},
{1, 0, 1}
};
int sr = 1, sc = 1;
int newColor = 2;
// Creating an instance of Solution class
Solution sol = new Solution();
// Function call to find the number of islands in given grid
int[][] ans = sol.floodFill(image, sr, sc, newColor);
System.out.println("Image after performing flood fill algorithm:\n");
for (int[] row : ans) {
for (int col : row) {
System.out.print(col + " ");
}
System.out.println();
}
}
}
class Solution:
def __init__(self):
# delRow and delCol for neighbors
self.delRow = [-1, 0, 1, 0]
self.delCol = [0, 1, 0, -1]
def isValid(self, i, j, n, m):
# Return false if pixel is invalid
if i < 0 or i >= n:
return False
if j < 0 or j >= m:
return False
# Return true if pixel is valid
return True
def dfs(self, row, col, ans, image, newColor, iniColor):
# color with new color
ans[row][col] = newColor
# Getting the dimensions of image
n = len(image)
m = len(image[0])
# Traverse the 4 neighbors
for i in range(4):
# Coordinates of new pixel
nrow = row + self.delRow[i]
ncol = col + self.delCol[i]
# check for valid, unvisited pixels
# having same initial color
if (
self.isValid(nrow, ncol, n, m) and
image[nrow][ncol] == iniColor and
ans[nrow][ncol] != newColor
):
# Recursively perform DFS
self.dfs(nrow, ncol, ans, image, newColor, iniColor)
def floodFill(self, image, sr, sc, newColor):
# Store initial color
iniColor = image[sr][sc]
# To store the updated image
ans = [row[:] for row in image]
# Start DFS traversal from start cell
self.dfs(sr, sc, ans, image, newColor, iniColor)
# Return the answer image
return ans
# Testing the function
image = [
[1, 1, 1],
[1, 1, 0],
[1, 0, 1]
]
sr, sc = 1, 1
newColor = 2
sol = Solution()
ans = sol.floodFill(image, sr, sc, newColor)
print("Image after performing flood fill algorithm:\n")
for row in ans:
print(" ".join(map(str, row)))
class Solution {
constructor() {
// delRow and delCol for neighbors
this.delRow = [-1, 0, 1, 0];
this.delCol = [0, 1, 0, -1];
}
isValid(i, j, n, m) {
// Return false if pixel is invalid
if (i < 0 || i >= n) return false;
if (j < 0 || j >= m) return false;
// Return true if pixel is valid
return true;
}
dfs(row, col, ans, image, newColor, iniColor) {
// color with new color
ans[row][col] = newColor;
// Getting the dimensions of image
const n = image.length;
const m = image[0].length;
// Traverse the 4 neighbors
for (let i = 0; i < 4; i++) {
// Coordinates of new pixel
const nrow = row + this.delRow[i];
const ncol = col + this.delCol[i];
// check for valid, unvisited pixels
// having same initial color
if (this.isValid(nrow, ncol, n, m)
&& image[nrow][ncol] == iniColor
&& ans[nrow][ncol] != newColor ) {
// Recursively perform DFS
this.dfs(nrow, ncol, ans, image, newColor, iniColor);
}
}
}
floodFill(image, sr, sc, newColor) {
// Store initial color
const iniColor = image[sr][sc];
// To store the updated image
const ans = image.map(row => row.slice());
// Start DFS traversal from start cell
this.dfs(sr, sc, ans, image, newColor, iniColor);
// Return the answer image
return ans;
}
}
// Testing the function
const image = [
[1, 1, 1],
[1, 1, 0],
[1, 0, 1]
];
const sr = 1, sc = 1;
const newColor = 2;
const sol = new Solution();
const ans = sol.floodFill(image, sr, sc, newColor);
console.log("Image after performing flood fill algorithm:\n");
ans.forEach(row => {
console.log(row.join(" "));
});
Time Complexity: O(N*M) (where N and M are the dimensions of image)
Space Complexity: O(N*M)
Q: How do we prevent infinite loops when filling?
A: Use a visited check by marking pixels with newColor or using a boolean visited array.
Q: What happens if newColor is the same as the original color?
A: If image[sr][sc] == newColor, return immediately, otherwise, the function will keep modifying the same color indefinitely.
Q: How would you modify this if pixels had multiple properties (e.g., color and texture)?
A: Use a multi-criteria flood fill, checking both color and other attributes.
Q: Can flood fill be used for maze-solving or pathfinding?
A: Yes, it can be adapted to explore all reachable paths in a maze.