See the original problem on HackerRank.
Solutions
This is a classical problem called Flood fill that can be solved in a relatively easy way: look for all pixels in the image that are connected to the start pixel by a path of the target color and changes them to the new color.
This algorithm is typically implemented using either recursion or a stack (or queue). This is a recursive implementation example:
|
|
Alternatively, here is a stack-based implementation:
|
|
Both are are linear in space and time, and apply a depth-first search pattern. These solutions pass all the test cases.
An optimization
The proposed solutions have three main disadvantages:
- use a lot of memory
- make a lot of pixel checks (at most four times per pixel)
- their access pattern is not cache-friendly (especially for the queue-based solution, since we process pixels level by level - the stack variant is a bit better since it dives deep in one direction, so it tends to stay in one region of the image longer, this means better locality in practice, but its access pattern is still less predictable).
A possibile optimization consists in the span filling (or scanline) approach. Instead of queuing individual pixels, we work row by row:
- from a seed pixel, fill the entire row left and right, noting the start and end (lx to rx)
- then scan the rows immediately above and below that run, looking for new runs to fill.
The key optimization: you only need to remember the start of each new run, not every pixel in it (since once you have a starting point, you can always re-expand left and right automatically). Using a stack or queue just controls the order you tackle runs (depth-first vs breadth-first) but either way you’re processing contiguous chunks of memory at a time, which is what makes it cache-friendly.
Here is a possible implementation:
|
|
Note that the “Expand left” and “Expand right” parts might be rewritten in terms of std::find_if (or std::find_if_not).
For the curious reader, there are other interesting ways to solve this problem:
- Disjoint set data structure
- special cases for binary images (e.g.
0and1) with bitwise operations - SIMD instructions