Flipping an Image: Row Reverse and Bit Flip
LeetCode's Flipping an Image is a great warm-up problem for matrix manipulation. It is rated easy, and the solution is short, but it teaches you two operations that show up in harder matrix problems: reversing rows and transforming values in place. The trick is recognizing that you can combine both steps into a single pass through each row.
The problem
You are given an n x n binary matrix (every value is 0 or 1). First, flip the image horizontally (reverse each row). Then, invert it (replace every 0 with 1 and every 1 with 0). Return the resulting matrix.
Input: [[1, 1, 0],
[1, 0, 1],
[0, 0, 0]]
Output: [[1, 0, 0],
[0, 1, 0],
[1, 1, 1]]
Row 0 starts as [1, 1, 0]. Reverse it to get [0, 1, 1]. Invert it to get [1, 0, 0]. Row 1 starts as [1, 0, 1]. Reverse it to get [1, 0, 1] (a palindrome, so no change). Invert it to get [0, 1, 0]. Row 2 starts as [0, 0, 0]. Reverse it to get [0, 0, 0]. Invert it to get [1, 1, 1].
The key insight
You can do both operations in a single pass using two pointers that walk inward from the edges of each row. At positions left and right, you swap the two values and flip them both. When left equals right (the middle element in an odd-length row), you just flip it without swapping.
There is also a neat observation: if row[left] and row[right] are the same value, then after reversing and inverting, both change. If they are different, they effectively cancel out and stay the same. You can use XOR to handle this elegantly.
Since the values are binary, flipping a bit is the same as XOR with 1: 0 ^ 1 = 1 and 1 ^ 1 = 0. This lets you combine the reverse and invert into one clean operation.
The solution
def flipAndInvertImage(image):
for row in image:
left, right = 0, len(row) - 1
while left <= right:
row[left], row[right] = row[right] ^ 1, row[left] ^ 1
left += 1
right -= 1
return image
Step-by-step walkthrough
Let's trace through image = [[1,1,0],[1,0,1],[0,0,0]]. Each step shows the matrix after processing one operation on one row.
Step 1: Start with the original matrix.
Input: [[1,1,0],[1,0,1],[0,0,0]]. We will process each row independently.
Step 2: Reverse row 0. [1,1,0] becomes [0,1,1].
Reverse row 0 in place. The first and last elements swap, the middle stays.
Step 3: Flip bits in row 0. [0,1,1] becomes [1,0,0].
Invert every bit: 0 becomes 1, 1 becomes 0. Row 0 is done.
Step 4: Reverse row 1. [1,0,1] becomes [1,0,1].
Row 1 is a palindrome, so reversing it produces the same row.
Step 5: Flip bits in row 1. [1,0,1] becomes [0,1,0].
Invert every bit. Row 1 is done.
Step 6: Reverse row 2. [0,0,0] becomes [0,0,0].
All zeros, so reversing changes nothing.
Step 7: Flip bits in row 2. [0,0,0] becomes [1,1,1].
All zeros become ones. Final result: [[1,0,0],[0,1,0],[1,1,1]].
Notice a few things:
- Row 1 is a palindrome. Reversing
[1, 0, 1]gives the same row. The invert step is what changes it to[0, 1, 0]. - Row 2 is all zeros. Reversing changes nothing, but inverting turns every 0 into a 1.
- The two-pointer approach handles both operations at once. By swapping and flipping simultaneously, you avoid making two separate passes.
The one-liner alternative
Python makes it possible to express this very concisely:
def flipAndInvertImage(image):
return [[1 - bit for bit in reversed(row)] for row in image]
This is clean and readable. It creates new lists rather than modifying in place, so it uses O(n) extra space per row. For an interview, the two-pointer in-place version shows stronger understanding, but the one-liner is worth mentioning.
Complexity analysis
Time: O(n^2). You visit every cell in the n x n matrix exactly once. Each cell involves a constant-time swap and XOR.
Space: O(1). The two-pointer approach modifies the matrix in place. No extra data structures are needed beyond the two index variables.
| Approach | Time | Space |
|---|---|---|
| Two-pass (reverse then invert) | O(n^2) | O(1) |
| Two-pointer single pass | O(n^2) | O(1) |
| List comprehension | O(n^2) | O(n^2) |
The two-pass and single-pass approaches have the same asymptotic complexity, but the single pass does fewer total operations and is more elegant.
The building blocks
This problem is built on two reusable bricks:
Two-pointer row reversal
The core pattern for reversing an array in place:
left, right = 0, len(arr) - 1
while left < right:
arr[left], arr[right] = arr[right], arr[left]
left += 1
right -= 1
You will see this in Rotate Image (transpose + reverse), Reverse String, and many other problems.
Bit flip with XOR
Toggling a binary value:
bit = bit ^ 1
This is a fundamental operation that appears in bit manipulation problems. XOR with 1 flips 0 to 1 and 1 to 0 without needing an if-else.
Edge cases
Before submitting, verify your solution handles:
- Single element matrix
[[0]]or[[1]]: reverse does nothing, just flip the single bit. - All zeros
[[0,0],[0,0]]: reverse does nothing, invert turns everything to 1. - All ones
[[1,1],[1,1]]: reverse does nothing, invert turns everything to 0. - Already inverted palindromes like
[[0,1,0]]: reversing a palindrome changes nothing, so only the invert matters. - Even-length rows like
[[1,0,0,1]]: no middle element, so the two pointers never overlap on the same index.
From understanding to recall
You have seen how the two-pointer approach combines reversing and inverting into a single pass. The logic is clean: swap the two values at left and right, XOR both with 1, move the pointers inward. But can you write it from memory during a timed session?
The moving parts here are small but specific: the while left <= right condition (not <, because you need to flip the middle element), the simultaneous swap-and-flip assignment, and remembering that XOR handles the inversion. Under pressure, it is easy to forget the <= or to flip before swapping and produce the wrong result.
Spaced repetition locks this pattern in. You write the two-pointer flip loop from scratch at increasing intervals until it becomes automatic. Then when you see a matrix transformation problem in an interview, the pattern is already in your fingers.
Related posts
- Rotate Image - Another in-place matrix transformation using transpose and row reversal
- Set Matrix Zeroes - In-place matrix modification with row and column markers
- Spiral Matrix - Traversing a matrix in a non-standard order using boundary tracking
CodeBricks breaks matrix manipulation patterns into their reusable pieces and drills them individually. You practice the two-pointer reverse, the XOR bit flip, and full matrix traversals until the code flows without hesitation.