The "Flipping an Image" problem asks you to take a binary matrix called image
(a 2D array of 0s and 1s), and perform two operations on each row:
Return the resulting 2D array after performing both operations on every row. Each row must be processed independently. You are guaranteed that the input is a valid binary matrix, and you should not reuse or overwrite elements in a way that would affect other rows.
Constraints:
image
is either 0 or 1.At first glance, the task seems to require two separate operations: first, reverse each row, and then invert each value. A brute-force approach would be to create a new matrix, copy each row in reverse order, and then flip each bit from 0 to 1 or 1 to 0. However, we can optimize this by noticing that both operations can be combined in a single pass.
If we process a row from both ends towards the center, we can swap and invert the values at the same time. This reduces the number of passes over the data, making the solution more efficient. It's similar to how you might reverse a word by swapping characters from both ends, but with the added twist of flipping the bits as you go.
The key insight is that flipping and inverting can be performed in-place, and for odd-length rows, the middle element just needs to be inverted once.
Here’s how we can efficiently solve the problem:
left
and right
) to traverse the row from both ends towards the center.
left
, right
):
left
and right
.left == right
(i.e., the middle of an odd-length row), just invert that element once.
left
forward and right
backward until they meet or cross.
We use in-place operations to save space, and handle each row independently to satisfy the problem constraints.
Let’s walk through a sample input:
Input:
image = [
[1, 1, 0],
[1, 0, 1],
[0, 0, 0]
]
Output:
[
[1,0,0],
[0,1,0],
[1,1,1]
]
Each row is processed independently, and the final matrix is returned.
Brute-force approach:
The optimized approach is preferable as it reduces extra space usage.
class Solution:
def flipAndInvertImage(self, image):
for row in image:
left, right = 0, len(row) - 1
while left <= right:
# Swap and invert
row[left], row[right] = row[right] ^ 1, row[left] ^ 1
if left == right:
# If pointers meet, only invert once
row[left] = row[left] ^ 1
left += 1
right -= 1
return image
class Solution {
public:
vector<vector<int>> flipAndInvertImage(vector<vector<int>>& image) {
for (auto& row : image) {
int left = 0, right = row.size() - 1;
while (left <= right) {
if (left == right) {
row[left] ^= 1;
} else {
int tempLeft = row[left] ^ 1;
int tempRight = row[right] ^ 1;
row[left] = tempRight;
row[right] = tempLeft;
}
left++;
right--;
}
}
return image;
}
};
class Solution {
public int[][] flipAndInvertImage(int[][] image) {
for (int[] row : image) {
int left = 0, right = row.length - 1;
while (left <= right) {
if (left == right) {
row[left] ^= 1;
} else {
int tempLeft = row[left] ^ 1;
int tempRight = row[right] ^ 1;
row[left] = tempRight;
row[right] = tempLeft;
}
left++;
right--;
}
}
return image;
}
}
var flipAndInvertImage = function(image) {
for (let row of image) {
let left = 0, right = row.length - 1;
while (left <= right) {
if (left === right) {
row[left] ^= 1;
} else {
let tempLeft = row[left] ^ 1;
let tempRight = row[right] ^ 1;
row[left] = tempRight;
row[right] = tempLeft;
}
left++;
right--;
}
}
return image;
};
The "Flipping an Image" problem is elegantly solved by combining the flipping and inverting steps into a single pass using a two-pointer approach. This reduces both the time and space complexity, making the solution efficient and clean. The key insight is recognizing that both operations can be performed in-place, and that each row can be processed independently. This approach demonstrates how careful observation and pointer manipulation can optimize seemingly straightforward problems.