3239. Minimum Number of Flips to Make Binary Grid Palindromic I
Problem Description
You have a binary matrix grid
with dimensions m x n
containing only 0s and 1s.
A row is palindromic if it reads the same from left to right as it does from right to left. Similarly, a column is palindromic if it reads the same from top to bottom as it does from bottom to top.
You can flip any cell in the grid, changing a 0
to 1
or a 1
to 0
.
Your goal is to make either all rows palindromic or all columns palindromic, using the minimum number of flips possible.
Return the minimum number of cells that need to be flipped to achieve this.
For example, if you have a row [1, 0, 1]
, it's already palindromic. But a row [1, 0, 0]
would need one flip (either change the first cell to 0
or the last cell to 1
) to become palindromic.
The solution works by:
- Counting how many flips are needed to make all rows palindromic (
cnt1
) - Counting how many flips are needed to make all columns palindromic (
cnt2
) - Returning the minimum of these two counts
For each row, we compare pairs of elements from opposite ends (first with last, second with second-last, etc.) and count mismatches. The same process is applied to columns. Since we need to choose between making all rows palindromic OR all columns palindromic, we take the option that requires fewer flips.
Intuition
The key insight is that we have two independent choices: make all rows palindromic OR make all columns palindromic. We don't need to do both, so we can calculate the cost of each option separately and pick the cheaper one.
For a sequence to be palindromic, elements at symmetric positions must be equal. For a row with n
elements, position 0
must equal position n-1
, position 1
must equal position n-2
, and so on. When these positions don't match, we need exactly one flip to fix the mismatch (we can flip either position to match the other).
Since flipping a cell only affects its own row and column, making rows palindromic doesn't interfere with making other rows palindromic. The same applies to columns. This independence means we can simply count the total mismatches across all rows (or all columns) to get the total flips needed.
The counting process only needs to check half of each row or column because we're comparing pairs. For a row of length n
, we only need to check the first n//2
positions against their mirror positions. Each mismatch we find represents exactly one required flip.
By calculating both cnt1
(flips needed for all rows) and cnt2
(flips needed for all columns), we can choose the option with fewer flips, giving us the optimal solution. This greedy approach works because the two options are mutually exclusive - we only need to satisfy one condition, not both.
Learn more about Two Pointers patterns.
Solution Approach
The implementation uses a straightforward counting approach with two separate passes through the grid.
Step 1: Initialize counters and get dimensions
m, n = len(grid), len(grid[0])
cnt1 = cnt2 = 0
We store the grid dimensions and initialize two counters: cnt1
for row flips and cnt2
for column flips.
Step 2: Count flips needed for all rows to be palindromic
for row in grid:
for j in range(n // 2):
if row[j] != row[n - j - 1]:
cnt1 += 1
For each row, we iterate through the first half of elements (j
from 0
to n//2 - 1
). We compare each element at position j
with its mirror element at position n - j - 1
. If they don't match, we increment cnt1
. We only check half the row because each comparison covers a pair of positions.
Step 3: Count flips needed for all columns to be palindromic
for j in range(n):
for i in range(m // 2):
if grid[i][j] != grid[m - i - 1][j]:
cnt2 += 1
For each column j
, we iterate through the first half of rows (i
from 0
to m//2 - 1
). We compare the element at row i
with its mirror element at row m - i - 1
in the same column. Mismatches increment cnt2
.
Step 4: Return the minimum
return min(cnt1, cnt2)
Since we need either all rows OR all columns to be palindromic (not both), we return the smaller count.
The time complexity is O(m * n)
as we traverse the entire grid twice. The space complexity is O(1)
since we only use two counter variables regardless of input size.
Ready to land your dream job?
Unlock your dream job with a 3-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through a small example with a 3x3 grid:
grid = [[1, 0, 0], [0, 1, 1], [1, 1, 0]]
Step 1: Count flips to make all rows palindromic (cnt1)
Row 0: [1, 0, 0]
- Compare position 0 with position 2:
1 != 0
β mismatch, need 1 flip - Position 1 (middle) doesn't need comparison
- Running total: cnt1 = 1
Row 1: [0, 1, 1]
- Compare position 0 with position 2:
0 != 1
β mismatch, need 1 flip - Running total: cnt1 = 2
Row 2: [1, 1, 0]
- Compare position 0 with position 2:
1 != 0
β mismatch, need 1 flip - Running total: cnt1 = 3
Step 2: Count flips to make all columns palindromic (cnt2)
Column 0: [1, 0, 1]
(reading top to bottom)
- Compare position 0 with position 2:
1 == 1
β match, no flip needed - Running total: cnt2 = 0
Column 1: [0, 1, 1]
- Compare position 0 with position 2:
0 != 1
β mismatch, need 1 flip - Running total: cnt2 = 1
Column 2: [0, 1, 0]
- Compare position 0 with position 2:
0 == 0
β match, no flip needed - Running total: cnt2 = 1
Step 3: Return minimum
- cnt1 = 3 (flips to make all rows palindromic)
- cnt2 = 1 (flips to make all columns palindromic)
- Return min(3, 1) = 1
The optimal solution is to make all columns palindromic with just 1 flip. We could flip grid[0][1]
from 0 to 1 (or grid[2][1]
from 1 to 0) to make column 1 palindromic: [1, 1, 1]
or [0, 0, 0]
.
Solution Implementation
1class Solution:
2 def minFlips(self, grid: List[List[int]]) -> int:
3 """
4 Find minimum flips needed to make either all rows or all columns palindromic.
5
6 Args:
7 grid: 2D binary matrix
8
9 Returns:
10 Minimum number of flips required
11 """
12 rows, cols = len(grid), len(grid[0])
13
14 # Count flips needed to make all rows palindromic
15 row_flips = 0
16 for row in grid:
17 # Check each pair of elements from both ends of the row
18 for j in range(cols // 2):
19 if row[j] != row[cols - j - 1]:
20 row_flips += 1
21
22 # Count flips needed to make all columns palindromic
23 col_flips = 0
24 for j in range(cols):
25 # Check each pair of elements from both ends of the column
26 for i in range(rows // 2):
27 if grid[i][j] != grid[rows - i - 1][j]:
28 col_flips += 1
29
30 # Return minimum of the two options
31 return min(row_flips, col_flips)
32
1class Solution {
2 /**
3 * Finds the minimum number of flips needed to make all rows palindromic
4 * or all columns palindromic in a binary grid.
5 *
6 * @param grid The input binary matrix
7 * @return The minimum number of flips required
8 */
9 public int minFlips(int[][] grid) {
10 int rowCount = grid.length;
11 int colCount = grid[0].length;
12
13 // Count flips needed to make all rows palindromic
14 int flipsForRowPalindromes = 0;
15
16 // Check each row for palindrome property
17 for (int[] currentRow : grid) {
18 // Compare elements from both ends moving towards center
19 for (int leftIdx = 0; leftIdx < colCount / 2; leftIdx++) {
20 int rightIdx = colCount - leftIdx - 1;
21
22 // If mirror elements don't match, a flip is needed
23 if (currentRow[leftIdx] != currentRow[rightIdx]) {
24 flipsForRowPalindromes++;
25 }
26 }
27 }
28
29 // Count flips needed to make all columns palindromic
30 int flipsForColPalindromes = 0;
31
32 // Check each column for palindrome property
33 for (int col = 0; col < colCount; col++) {
34 // Compare elements from top and bottom moving towards center
35 for (int topIdx = 0; topIdx < rowCount / 2; topIdx++) {
36 int bottomIdx = rowCount - topIdx - 1;
37
38 // If mirror elements don't match, a flip is needed
39 if (grid[topIdx][col] != grid[bottomIdx][col]) {
40 flipsForColPalindromes++;
41 }
42 }
43 }
44
45 // Return the minimum flips between row-wise and column-wise approaches
46 return Math.min(flipsForRowPalindromes, flipsForColPalindromes);
47 }
48}
49
1class Solution {
2public:
3 int minFlips(vector<vector<int>>& grid) {
4 int rowCount = grid.size();
5 int colCount = grid[0].size();
6
7 // Count flips needed to make all rows palindromic
8 int rowFlips = 0;
9 for (const auto& row : grid) {
10 // Check each pair of elements from both ends of the row
11 for (int left = 0; left < colCount / 2; ++left) {
12 int right = colCount - left - 1;
13 // If the pair doesn't match, we need a flip
14 if (row[left] != row[right]) {
15 ++rowFlips;
16 }
17 }
18 }
19
20 // Count flips needed to make all columns palindromic
21 int colFlips = 0;
22 for (int col = 0; col < colCount; ++col) {
23 // Check each pair of elements from both ends of the column
24 for (int top = 0; top < rowCount / 2; ++top) {
25 int bottom = rowCount - top - 1;
26 // If the pair doesn't match, we need a flip
27 if (grid[top][col] != grid[bottom][col]) {
28 ++colFlips;
29 }
30 }
31 }
32
33 // Return the minimum flips needed (either make all rows or all columns palindromic)
34 return min(rowFlips, colFlips);
35 }
36};
37
1/**
2 * Finds the minimum number of flips needed to make either all rows or all columns palindromic
3 * @param grid - 2D binary matrix
4 * @returns Minimum number of flips required
5 */
6function minFlips(grid: number[][]): number {
7 // Get dimensions of the grid
8 const rows: number = grid.length;
9 const cols: number = grid[0].length;
10
11 // Counter for flips needed to make all rows palindromic
12 let rowFlipsCount: number = 0;
13 // Counter for flips needed to make all columns palindromic
14 let colFlipsCount: number = 0;
15
16 // Calculate flips needed for each row to become palindromic
17 for (const row of grid) {
18 // Check pairs from start and end of the row
19 for (let leftIndex = 0; leftIndex < cols / 2; leftIndex++) {
20 const rightIndex = cols - 1 - leftIndex;
21 // If symmetric positions don't match, a flip is needed
22 if (row[leftIndex] !== row[rightIndex]) {
23 rowFlipsCount++;
24 }
25 }
26 }
27
28 // Calculate flips needed for each column to become palindromic
29 for (let colIndex = 0; colIndex < cols; colIndex++) {
30 // Check pairs from top and bottom of the column
31 for (let topIndex = 0; topIndex < rows / 2; topIndex++) {
32 const bottomIndex = rows - 1 - topIndex;
33 // If symmetric positions don't match, a flip is needed
34 if (grid[topIndex][colIndex] !== grid[bottomIndex][colIndex]) {
35 colFlipsCount++;
36 }
37 }
38 }
39
40 // Return the minimum between making all rows or all columns palindromic
41 return Math.min(rowFlipsCount, colFlipsCount);
42}
43
Time and Space Complexity
Time Complexity: O(m Γ n)
, where m
is the number of rows and n
is the number of columns in the matrix grid
.
The algorithm consists of two main parts:
- First loop: Iterates through all
m
rows, and for each row, checksn/2
pairs of elements. This results inO(m Γ n/2)
operations. - Second loop: Iterates through all
n
columns, and for each column, checksm/2
pairs of elements. This results inO(n Γ m/2)
operations.
The total time complexity is O(m Γ n/2) + O(n Γ m/2) = O(m Γ n)
.
Space Complexity: O(1)
The algorithm only uses a constant amount of extra space for variables m
, n
, cnt1
, cnt2
, and loop counters i
and j
. No additional data structures that scale with input size are created.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Incorrectly Counting Total Flips Instead of Minimum Required
A common mistake is thinking that when two elements don't match (e.g., row[j] != row[n-j-1]
), you need to flip both of them. This leads to counting 2 flips per mismatch instead of 1.
Incorrect approach:
for row in grid:
for j in range(n // 2):
if row[j] != row[n - j - 1]:
cnt1 += 2 # WRONG: Only need to flip one element
Why it's wrong: When making a palindrome, if position j
has value 1
and position n-j-1
has value 0
, you only need to flip ONE of them to make them match. You can either flip the 1
to 0
OR flip the 0
to 1
.
Correct approach: Count 1 flip per mismatched pair, as shown in the original solution.
2. Double-Counting Middle Elements in Odd-Length Rows/Columns
When a row or column has odd length, there's a middle element that doesn't have a pair. Some might incorrectly try to include it in the palindrome check.
Incorrect approach:
for row in grid:
for j in range((n + 1) // 2): # WRONG: May process middle element
if row[j] != row[n - j - 1]:
cnt1 += 1
Why it's wrong: For odd-length arrays, the middle element (at index n//2
) is compared with itself when j = n//2
, resulting in row[n//2] != row[n//2]
which is always false. While this doesn't affect correctness, it's unnecessary computation.
Correct approach: Use range(n // 2)
which automatically excludes the middle element in odd-length cases, since the middle element is already palindromic by definition.
3. Attempting to Optimize by Making Both Rows AND Columns Palindromic
Some might think they can find an optimal solution that makes both rows and columns palindromic simultaneously.
Why it's wrong: The problem asks for EITHER all rows OR all columns to be palindromic, not both. Trying to achieve both simultaneously would likely require more flips and isn't what the problem asks for.
Correct approach: Calculate the minimum flips for rows and columns separately, then return the smaller value.
How would you design a stack which has a function min
that returns the minimum element in the stack, in addition to push
and pop
? All push
, pop
, min
should have running time O(1)
.
Recommended Readings
Tech Interview Pattern Two Pointers Introduction If you prefer videos here's a super quick introduction to Two Pointers div class responsive iframe iframe src https www youtube com embed xZ4AfXHQ1VQ title YouTube video player frameborder 0 allow accelerometer autoplay clipboard write encrypted media gyroscope picture in picture allowfullscreen iframe div Two pointers is a common interview
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Donβt Miss This!