Mirror image of a 2D array

AS
Ackshaey Singh
Difficulty Easy
Time Complexity
O(m * n)
Space Complexity
O(m * n)
Matrix
Firecode

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

  1. Single pixel (1x1 array): The mirror is itself
  2. Single column: Reversing one element per row changes nothing
  3. Single row: The result is simply the reversed row
  4. 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 - 1 in the input
  • Column 1 in the output comes from column numCols - 2 in the input
  • Column col in the output comes from column numCols - 1 - col in 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:

  1. Read the dimensions of the input array
  2. Allocate a new array with the same dimensions
  3. For each cell, copy the value from the corresponding reversed column
  4. 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] = 0
  • col=1: mirrorImage[0][1] = image[0][1] = 255
  • col=2: mirrorImage[0][2] = image[0][0] = 255

Row 1:

  • col=0: mirrorImage[1][0] = image[1][2] = 0
  • col=1: mirrorImage[1][1] = image[1][1] = 255
  • col=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

  1. 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.

  2. 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).

  3. Off-by-one in the index formula: Using numCols - col instead of numCols - 1 - col causes an ArrayIndexOutOfBoundsException. Remember that array indices are zero-based.

  4. Hardcoding dimensions: Using image.length and image[0].length keeps 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 col in the output maps to column numCols - 1 - col in 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;
    }
}

Frequently Asked Questions

What does it mean to flip an image on its vertical axis?
Flipping on the vertical axis means reversing the order of columns in each row. The leftmost column becomes the rightmost, and vice versa. Each row keeps its original position, but the elements within each row are reversed. Think of it like holding the image up to a mirror.
Why do we create a new array instead of modifying the input?
Creating a new array preserves the original data, which is important if other parts of the program still need it. Modifying the input (an in-place approach) is possible but risks losing data mid-swap if not handled carefully. The problem explicitly requires returning a new array.
What is the time complexity of mirror imaging a 2D array?
The time complexity is O(m * n) where m is the number of rows and n is the number of columns. Every pixel must be copied exactly once to its mirrored position in the output array, so the work scales linearly with the total number of elements.
What is the space complexity of the mirror image solution?
The space complexity is O(m * n) because we allocate a new 2D array of the same dimensions as the input. If an in-place solution were allowed, it could be done in O(1) extra space by swapping elements within each row.
Can this problem be solved in-place?
Yes, if the problem allowed modifying the input. You would swap the first and last elements of each row, then the second and second-to-last, and so on. This would use O(1) extra space. However, this particular problem requires returning a new array without modifying the original.
How does the column index mapping formula work?
For a row with numCols columns, column index col in the output maps to column numCols - 1 - col in the input. When col is 0, you read from index numCols - 1 (the last column). When col is numCols - 1, you read from index 0 (the first column). This reverses the column order for each row.
What edge cases should I consider for the mirror image problem?
Consider a single-pixel image (1x1 array), which should return itself unchanged. A single-column image also returns the same values since reversing one element changes nothing. A single-row image is simply a reversed array. All of these follow naturally from the general algorithm without special handling.
How is this problem different from rotating an image 90 degrees?
Mirror imaging reverses columns within each row, keeping row positions fixed. A 90-degree rotation moves elements between rows and columns, changing the dimensions from m x n to n x m. Mirror imaging preserves the original dimensions and is simpler to implement.