← Home

733. Flood Fill

LeetCode article · C++ solution
Website made by wuisabel-gif · Original C++ code by keineahnung2345
graph traversalC++Markdown
733

This is one of those problems where the clean idea matters more than the amount of code. For 733. Flood Fill, the solution in this repository is mainly a graph traversal solution.

Guide

What?

The code is easier to read if we treat it as a controlled search through possible states. Instead of trying to be clever immediately, read the code as a sequence of questions:

  • What state are we keeping?
  • How do we move from one state to the next?
  • When do we know the answer is already determined?

For this file, the main tools are: graph traversal.

Guide

When?

Use this approach when the hard part is not syntax, but deciding what must stay true after every update. The accepted code reduces that pressure by storing exactly the information that remains useful later.

The important function names to track are isVisited, dfs.

Guide

Why?

The solution works because it narrows the problem until every update has a clear reason to exist.

  • The queue gives the solution a level-by-level or frontier-style traversal.
  • The two-dimensional vector is the memory of the solution: grid state, DP state, or adjacency shape.
  • The final return is not magic; it is the invariant after the loops or recursion have finished doing their accounting.

Guide

How?

Walk through the solution in this order:

  1. Start from the smallest reliable state.
  2. Expand one legal move at a time.
  3. Cache, count, or merge information as soon as it becomes settled.
  4. Let the final stored value answer the original question.

The most important competitive-programming habit here is to trust the invariant. Once the invariant is right, the loops become much less scary.

Guide

Complexity

  • Time: O(n) to O(n log n), depending on the dominant loop or data structure operation
  • Space: O(n) in the usual case for auxiliary containers or recursion

Guide

C++ Solution

Your submission

The accepted solution

solution.cpp
01/**
02An image is represented by a 2-D array of integers, each integer representing the pixel value of the image (from 0 to 65535).
03
04Given a coordinate (sr, sc) representing the starting pixel (row and column) of the flood fill, and a pixel value newColor, "flood fill" the image.
05
06To perform a "flood fill", consider the starting pixel, plus any pixels connected 4-directionally to the starting pixel of the same color as the starting pixel, plus any pixels connected 4-directionally to those pixels (also with the same color as the starting pixel), and so on. Replace the color of all of the aforementioned pixels with the newColor.
07
08At the end, return the modified image.
09
10Example 1:
11Input: 
12image = [[1,1,1],[1,1,0],[1,0,1]]
13sr = 1, sc = 1, newColor = 2
14Output: [[2,2,2],[2,2,0],[2,0,1]]
15Explanation: 
16From the center of the image (with position (sr, sc) = (1, 1)), all pixels connected 
17by a path of the same color as the starting pixel are colored with the new color.
18Note the bottom corner is not colored 2, because it is not 4-directionally connected
19to the starting pixel.
20Note:
21
22The length of image and image[0] will be in the range [1, 50].
23The given starting pixel will satisfy 0 <= sr < image.length and 0 <= sc < image[0].length.
24The value of each color in image[i][j] and newColor will be an integer in [0, 65535].
25**/
26
27//Runtime: 28 ms, faster than 98.25% of C++ online submissions for Flood Fill.
28//Memory Usage: 10.5 MB, less than 98.44% of C++ online submissions for Flood Fill.
29class Solution {
30public:
31    queue<pair<int, int>> q;
32    vector<pair<int, int>> visited;
33    
34    bool isVisited(int r, int c){
35        return find(visited.begin(), visited.end(), make_pair(r, c))!=visited.end();
36    }
37    
38    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int newColor) {
39        int oldColor = image[sr][sc];
40        q.push(make_pair(sr, sc));
41        
42        //BFS a graph
43        while(!q.empty()){
44            pair<int, int> p = q.front();
45            q.pop();
46            sr = p.first;
47            sc = p.second;
48            // cout << sr << " " << sc << endl;
49            
50            image[sr][sc] = newColor;
51            visited.push_back(make_pair(sr, sc));
52            
53            if(sr > 0 && !isVisited(sr-1, sc) && image[sr-1][sc]==oldColor){
54                q.push(make_pair(sr-1, sc));
55            }
56            if(sc > 0 && !isVisited(sr, sc-1) && image[sr][sc-1]==oldColor){
57                q.push(make_pair(sr, sc-1));
58            }
59            if(sr < image.size()-1 && !isVisited(sr+1, sc) && image[sr+1][sc]==oldColor){
60                q.push(make_pair(sr+1, sc));
61            }
62            if(sc < image[0].size()-1 && !isVisited(sr, sc+1) && image[sr][sc+1]==oldColor){
63                q.push(make_pair(sr, sc+1));
64            }
65        }
66        
67        return image;
68    }
69};
70
71//another BFS
72//Runtime: 20 ms, faster than 82.96% of C++ online submissions for Flood Fill.
73//Memory Usage: 15 MB, less than 11.11% of C++ online submissions for Flood Fill.
74class Solution {
75public:
76    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int newColor) {
77        int m = image.size();
78        if(m == 0) return vector<vector<int>>();
79        int n = image[0].size();
80        if(n == 0) return vector<vector<int>>();
81        
82        queue<vector<int>> q;
83        vector<vector<bool>> visited(m, vector(n, false));
84        vector<int> cur;
85        vector<vector<int>> dirs = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
86        int oldColor = image[sr][sc];
87        
88        q.push({sr, sc});
89        visited[sr][sc] = true;
90        
91        while(!q.empty()){
92            cur = q.front(); q.pop();
93            image[cur[0]][cur[1]] = newColor;
94            
95            for(vector<int>& dir : dirs){
96                int nr = cur[0] + dir[0];
97                int nc = cur[1] + dir[1];
98                if(nr >= 0 && nr < m && nc >= 0 && nc < n && !visited[nr][nc] && image[nr][nc] == oldColor){
99                    visited[nr][nc] = true;
100                    q.push({nr, nc});
101                }
102            }
103        }
104        
105        return image;
106    }
107};
108
109/**
110Approach #1: Depth-First Search [Accepted]
111Intuition
112
113We perform the algorithm explained in the problem description: paint the starting pixels, plus adjacent pixels of the same color, and so on.
114
115Algorithm
116
117Say color is the color of the starting pixel. Let's floodfill the starting pixel: we change the color of that pixel to the new color, then check the 4 neighboring pixels to make sure they are valid pixels of the same color, and of the valid ones, we floodfill those, and so on.
118
119We can use a function dfs to perform a floodfill on a target pixel.
120**/
121
122/**
123Complexity Analysis
124
125Time Complexity: O(N), where N is the number of pixels in the image. We might process every pixel.
126
127Space Complexity: O(N), the size of the implicit call stack when calling dfs.
128**/
129
130//Runtime: 24 ms, faster than 100.00% of C++ online submissions for Flood Fill.
131//Memory Usage: 10.2 MB, less than 99.22% of C++ online submissions for Flood Fill.
132
133class Solution {
134public:
135    int oc;
136    int nc;
137    
138    void dfs(vector<vector<int>>& image, int r, int c){
139        if(image[r][c] == oc){
140            image[r][c] = nc;
141            if(r > 0) dfs(image, r-1, c);
142            if(c > 0) dfs(image, r, c-1);
143            if(r < image.size()-1) dfs(image, r+1, c);
144            if(c < image[0].size()-1) dfs(image, r, c+1);
145        }
146    }
147    
148    vector<vector<int>> floodFill(vector<vector<int>>& image, int sr, int sc, int newColor) {
149        oc = image[sr][sc];
150        nc = newColor;
151        
152        if(oc != nc){
153            dfs(image, sr, sc);
154        }
155        return image;
156    }
157};

Cost

Complexity

Time
O(n) to O(n log n), depending on the dominant loop or data structure operation
Dominated by the main traversal, recursion, or data-structure operations in the code.
Space
O(n) in the usual case for auxiliary containers or recursion
Auxiliary state plus the answer structure where the problem requires one.