Mirror image of a 2D array
You are ten minutes into a phone screen and the interviewer pulls up a shared editor. "Let's start with something straightforward," they say. "Given a grayscale image stored as a 2D array of pixel values, write a function that flips it horizontally, like holding it up to a mirror." It sounds simple, and it is, but the interviewer is watching how you handle array indexing, whether you create a clean new array instead of mutating the input, and whether you can articulate the column mapping formula clearly. This is the kind of warm-up problem that sets the tone for the rest of the interview.
TL;DR
Create a new 2D array with the same dimensions as the input. Iterate over every row and column, copying each element from the input's reversed column position: mirrorImage[row][col] = image[row][numCols - 1 - col]. This runs in O(m * n) time and O(m * n) space, where m is the number of rows and n the number of columns. The formula numCols - 1 - col is the core insight that maps each column to its mirror position.
Prefer a different language? Jump to solutions in other languages.
Understanding the Problem
Given a black and white image represented as a 2D array of integers (values between 0 and 255), return a new array representing the image flipped on its vertical axis. The leftmost column becomes the rightmost, and vice versa.
Here is the example from the problem statement: mirrorImage([[255, 0, 0], [255, 0, 0]]) returns [[0, 0, 255], [0, 0, 255]].
Before (original image):
Loading visualization...
The green cells hold 255 (white pixels) on the left side of the image.
After (mirrored image):
Loading visualization...
After mirroring, those white pixels have moved to the right side. Every row still has the same set of values, just in reversed column order.
Constraints
- The image contains at least 1 pixel
- Pixel values range from 0 to 255
- Return a new array (do not modify the input)
- 1 ≤ rows ≤ 1000, 1 ≤ columns ≤ 1000
Edge Cases
- Single pixel (1x1 array): The mirror is itself
- Single column: Reversing one element per row changes nothing
- Single row: The result is simply the reversed row
- Square image: Works identically to rectangular images
Building the Intuition
Think about what happens when you look at yourself in a mirror. Your left hand appears on the right side of the reflection, and your right hand appears on the left. Nothing moves vertically, only horizontally. The same principle applies here: each row keeps its position, but the elements within each row are reversed.
For a row with numCols columns, the mapping is:
- Column 0 in the output comes from column
numCols - 1in the input - Column 1 in the output comes from column
numCols - 2in the input - Column
colin the output comes from columnnumCols - 1 - colin the input
This diagram shows how source columns map to destination columns for a 3-column row:
Loading visualization...
The arrows show each source column crossing over to its mirrored position. Column 0 goes to column 2, column 1 stays at column 1 (the center), and column 2 goes to column 0.
The Formula
The general formula is mirrorImage[row][col] = image[row][numCols - 1 - col]. Let's verify it with a 3x3 grid. If the original looks like this:
Loading visualization...
Then the mirrored version reverses each row's column order:
Loading visualization...
Notice how 1 moved from position (0,0) to (0,2), while 3 moved from (0,2) to (0,0). The center column (5 at position (1,1)) stays put because numCols - 1 - 1 = 1.
Implementation
The algorithm is straightforward:
- Read the dimensions of the input array
- Allocate a new array with the same dimensions
- For each cell, copy the value from the corresponding reversed column
- Return the new array
public class Solution {
public int[][] mirrorImage(int[][] image) {
int numRows = image.length, numCols = image[0].length;
int[][] mirrorImage = new int[numRows][numCols];
for (int row = 0; row < numRows; row++) {
for (int col = 0; col < numCols; col++) {
mirrorImage[row][col] = image[row][numCols - 1 - col];
}
}
return mirrorImage;
}
}
Let's trace through this with the test case [[255, 255, 0], [255, 255, 0]]:
Row 0:
col=0:mirrorImage[0][0] = image[0][2] = 0col=1:mirrorImage[0][1] = image[0][1] = 255col=2:mirrorImage[0][2] = image[0][0] = 255
Row 1:
col=0:mirrorImage[1][0] = image[1][2] = 0col=1:mirrorImage[1][1] = image[1][1] = 255col=2:mirrorImage[1][2] = image[1][0] = 255
Result: [[0, 255, 255], [0, 255, 255]]. The white pixels (255) that were on the left have moved to the right.
Complexity Analysis
Time Complexity: O(m * n)
Every element in the m x n grid is visited exactly once. The inner loop body performs a single array assignment, which is O(1). So the total work is proportional to the number of pixels.
Space Complexity: O(m * n)
We allocate a new array of the same size as the input. The loop variables use O(1) additional space, but the output array dominates.
If the problem allowed in-place modification, you could swap elements within each row using two pointers (one from the left, one from the right) to achieve O(1) extra space. But since the problem requires a new array, O(m * n) is unavoidable.
Common Mistakes
-
Modifying the input array: The problem explicitly says to return a new array. Some candidates try to reverse rows in-place and return the same reference, which violates the contract.
-
Confusing row and column reversal: A vertical axis flip reverses columns, not rows. Reversing the order of rows would be a horizontal axis flip (upside-down).
-
Off-by-one in the index formula: Using
numCols - colinstead ofnumCols - 1 - colcauses anArrayIndexOutOfBoundsException. Remember that array indices are zero-based. -
Hardcoding dimensions: Using
image.lengthandimage[0].lengthkeeps the solution general. Avoid assuming square images or fixed sizes.
Interview Tips
This is a warm-up problem, so interviewers are evaluating your fundamentals. A few things that make a good impression:
- Ask about mutation: Clarify whether you should modify the input or return a new array. This shows you think about side effects.
- State the formula clearly: Saying "column
colin the output maps to columnnumCols - 1 - colin the input" demonstrates you understand the core transformation. - Mention the in-place alternative: Even though the problem asks for a new array, mentioning that an in-place swap would reduce space to O(1) shows awareness of optimization opportunities.
- Trace through a small example: Walk through a 2x3 grid on the whiteboard to verify your indices before writing code.
Related Problems
Once you're comfortable with this problem, try these related matrix transformations:
- Rotate an image 90 degrees (requires transposing rows and columns)
- Matrix spiral traversal (reading elements in spiral order)
- Zero out rows and columns (modifying a matrix based on zero positions)
This problem and hundreds of others are available on Firecode, where over 50,000 engineers have practiced for technical interviews and landed roles at top companies. If you are preparing for interviews, consistent practice with problems like this builds the muscle memory that makes harder problems feel manageable.
Solutions in Other Languages
Python
class Solution:
def mirror_image(self, image):
num_rows = len(image)
num_cols = len(image[0])
mirror_image = [[0 for col in range(num_cols)] for row in range(num_rows)]
for row in range(num_rows):
for col in range(num_cols):
mirror_image[row][col] = image[row][num_cols - 1 - col]
return mirror_image
JavaScript
class Solution {
mirrorImage(image) {
const numRows = image.length, numCols = image[0].length;
const mirrorImage = [...Array(numRows)].map(_ => Array(numCols));
for (let row = 0; row < numRows; row++) {
for (let col = 0; col < numCols; col++) {
mirrorImage[row][col] = image[row][numCols - 1 - col];
}
}
return mirrorImage;
}
}
TypeScript
class Solution {
mirrorImage(image: number[][]): number[][] {
const numRows = image.length, numCols = image[0].length;
const mirrorImage: number[][] = [...Array(numRows)].map(_ => Array(numCols));
for (let row = 0; row < numRows; row++) {
for (let col = 0; col < numCols; col++) {
mirrorImage[row][col] = image[row][numCols - 1 - col];
}
}
return mirrorImage;
}
}
C++
#include <vector>
class Solution {
public:
std::vector<std::vector<int>>
mirrorImage(std::vector<std::vector<int>> image) {
auto rows = image.size(), cols = image[0].size();
std::vector<std::vector<int>> mirrorImage;
mirrorImage.resize(rows, std::vector<int>(cols));
for (auto r = 0; r < rows; ++r) {
for (auto c = 0; c < cols; ++c) {
mirrorImage[r][c] = image[r][cols - 1 - c];
}
}
return mirrorImage;
}
};
Go
func MirrorImage(image [][]int) [][]int {
rows, cols := len(image), len(image[0])
mirrorImage := make([][]int, rows)
for i := 0; i < rows; i++ {
mirrorImage[i] = make([]int, cols)
}
for r := 0; r < rows; r++ {
for c := 0; c < cols; c++ {
mirrorImage[r][c] = image[r][cols-1-c]
}
}
return mirrorImage
}
Scala
class Solution {
def mirrorImage(image: Array[Array[Int]]): Array[Array[Int]] = {
val numRows = image.length
val numCols = image(0).length
val mirrorImage = Array.ofDim[Int](numRows, numCols)
for (row <- 0 until numRows) {
for (col <- 0 until numCols) {
mirrorImage(row)(col) = image(row)(numCols - 1 - col)
}
}
mirrorImage
}
}
Kotlin
class Solution {
fun mirrorImage(image: Array<IntArray>): Array<IntArray> {
val numRows = image.size
val numCols = image[0].size
val mirrorImage = Array(numRows) { IntArray(numCols) }
for (row in 0 until numRows) {
for (col in 0 until numCols) {
mirrorImage[row][col] = image[row][numCols - 1 - col]
}
}
return mirrorImage
}
}
Swift
class Solution {
func mirrorImage(_ image: [[Int]]) -> [[Int]] {
let numRows = image.count
let numCols = image[0].count
var mirrorImage = (0..<numRows).map { _ in Array(repeating: 0, count: numCols) }
for row in 0..<numRows {
for col in 0..<numCols {
mirrorImage[row][col] = image[row][numCols - 1 - col]
}
}
return mirrorImage
}
}
Rust
pub fn mirror_image(image: Vec<Vec<i32>>) -> Vec<Vec<i32>> {
let num_rows = image.len();
let num_cols = image[0].len();
let mut mirror_image = vec![vec![0; num_cols]; num_rows];
for row in 0..num_rows {
for col in 0..num_cols {
mirror_image[row][col] = image[row][num_cols - 1 - col];
}
}
mirror_image
}
Ruby
class Solution
def mirror_image(image)
num_rows, num_cols = image.length, image[0].length
mirror_image = Array.new(num_rows) { Array.new(num_cols) }
(0...num_rows).each do |row|
(0...num_cols).each do |col|
mirror_image[row][col] = image[row][num_cols - 1 - col]
end
end
mirror_image
end
end
Dart
class Solution {
List<List<int>> mirrorImage(List<List<int>> image) {
int numRows = image.length, numCols = image[0].length;
List<List<int>> mirrorImage =
List.generate(numRows, (_) => List.filled(numCols, 0));
for (int row = 0; row < numRows; row++) {
for (int col = 0; col < numCols; col++) {
mirrorImage[row][col] = image[row][numCols - 1 - col];
}
}
return mirrorImage;
}
}
C#
public class Solution {
public int[][] MirrorImage(int[][] image) {
int numRows = image.Length, numCols = image[0].Length;
int[][] mirrorImage = new int[numRows][];
for (int row = 0; row < numRows; row++) {
mirrorImage[row] = new int[numCols];
for (int col = 0; col < numCols; col++) {
mirrorImage[row][col] = image[row][numCols - 1 - col];
}
}
return mirrorImage;
}
}
PHP
class Solution {
public function mirrorImage(array $image): array {
$numRows = count($image);
$numCols = count($image[0]);
$mirrorImage = [];
for ($row = 0; $row < $numRows; $row++) {
for ($col = 0; $col < $numCols; $col++) {
$mirrorImage[$row][$col] = $image[$row][$numCols - 1 - $col];
}
}
return $mirrorImage;
}
}