Facebook Pixel

3240. Minimum Number of Flips to Make Binary Grid Palindromic II

Problem Description

You have an m x n binary matrix grid 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 find the minimum number of flips needed to satisfy both of these conditions:

  1. Every row in the grid must be palindromic
  2. Every column in the grid must be palindromic
  3. The total count of 1s in the entire grid must be divisible by 4

The problem asks you to return this minimum number of flips required.

For example, if you have a grid where some rows or columns are not palindromic, you need to flip certain cells to make them palindromic. Additionally, after all flips are done, the total number of 1s in the grid must be a multiple of 4 (like 0, 4, 8, 12, etc.).

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

Let's think about what happens when both rows and columns need to be palindromic simultaneously.

For any position (i, j) in the grid, if row i is palindromic, then grid[i][j] must equal grid[i][n-j-1]. Similarly, if column j is palindromic, then grid[i][j] must equal grid[m-i-1][j].

But here's the key insight: these constraints create groups of 4 cells that must all have the same value! Consider the four positions:

  • (i, j)
  • (i, n-j-1)
  • (m-i-1, j)
  • (m-i-1, n-j-1)

Due to the palindrome constraints:

  • grid[i][j] must equal grid[i][n-j-1] (row i is palindromic)
  • grid[m-i-1][j] must equal grid[m-i-1][n-j-1] (row m-i-1 is palindromic)
  • grid[i][j] must equal grid[m-i-1][j] (column j is palindromic)
  • grid[i][n-j-1] must equal grid[m-i-1][n-j-1] (column n-j-1 is palindromic)

This means all four cells must be equal! So we can process the grid in groups of 4 symmetric cells. For each group, we count how many are currently 1s and decide whether it's cheaper to flip them all to 0 or all to 1.

The tricky part comes with odd dimensions. When m or n is odd, we have middle rows or columns that don't form complete 4-cell groups:

  • If both m and n are odd, there's a center cell that maps to itself under both reflections. Since the total number of 1s must be divisible by 4, and all other cells come in groups of 2 or 4, this center cell must be 0.

  • If only one dimension is odd, we have pairs of cells in the middle row/column that must be equal due to palindrome constraints. Here's where it gets interesting: these pairs contribute either 0 or 2 to the count of 1s.

To satisfy the divisibility by 4 requirement, we need to be careful about how many pairs contribute 2 (i.e., both cells are 1). If we already have an even number of such pairs, we're good. But if we have an odd number of pairs contributing 2 (making the total count 2 mod 4), we need to either:

  • Change one differing pair to both be 1s (if such pairs exist)
  • Or change one matching pair of 1s to 0s (if no differing pairs exist)

This ensures the final count of 1s is divisible by 4 while minimizing flips.

Learn more about Two Pointers patterns.

Solution Approach

Let's walk through the implementation step by step:

Step 1: Process 4-cell groups

We iterate through the top-left quadrant of the grid using i in range(m // 2) and j in range(n // 2). For each position (i, j), we identify its three symmetric counterparts:

  • (x, j) where x = m - i - 1 (vertically symmetric)
  • (i, y) where y = n - j - 1 (horizontally symmetric)
  • (x, y) (diagonally symmetric)

We count how many of these 4 cells are currently 1:

cnt1 = grid[i][j] + grid[x][j] + grid[i][y] + grid[x][y]

To make all 4 cells the same, we can either:

  • Flip cnt1 cells to make them all 0
  • Flip 4 - cnt1 cells to make them all 1

We choose the minimum: min(cnt1, 4 - cnt1) and add it to our answer.

Step 2: Handle the center cell (if both dimensions are odd)

If both m and n are odd, there's a center cell at (m // 2, n // 2). Since all other cells come in groups of 2 or 4, and the total must be divisible by 4, this center cell must be 0. If it's currently 1, we need one flip:

if m % 2 and n % 2:
    ans += grid[m // 2][n // 2]

Step 3: Handle middle row/column

Initialize diff = 0 to count pairs that differ, and cnt1 = 0 to count the number of 1s from matching pairs.

If m is odd (middle row exists):

for j in range(n // 2):
    if grid[m // 2][j] == grid[m // 2][n - j - 1]:
        cnt1 += grid[m // 2][j] * 2  # Add 2 if both are 1, 0 if both are 0
    else:
        diff += 1  # Count differing pairs

Similarly, if n is odd (middle column exists):

for i in range(m // 2):
    if grid[i][n // 2] == grid[m - i - 1][n // 2]:
        cnt1 += grid[i][n // 2] * 2
    else:
        diff += 1

Step 4: Determine additional flips needed

Now we need to ensure the total count of 1s is divisible by 4:

  • If cnt1 % 4 == 0: The count is already good. We just need to fix the diff differing pairs by making them match (doesn't matter if they become 0 or 1), requiring diff flips.

  • If cnt1 % 4 == 2: We have an issue.

    • If diff > 0: We can fix one differing pair by making both cells 1, adding 2 to our count (making it divisible by 4), and fix the remaining diff - 1 pairs however we want. Total: diff flips.
    • If diff == 0: All pairs already match, but we have the wrong count. We need to flip one matching pair of 1s to 0s, requiring 2 flips.

This is elegantly captured in the expression:

ans += diff if cnt1 % 4 == 0 or diff else 2

The condition evaluates to diff when either cnt1 % 4 == 0 or diff > 0, and 2 when cnt1 % 4 != 0 and diff == 0.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through a concrete example to illustrate the solution approach.

Consider this 3Γ—4 grid:

1 0 0 1
0 1 1 0
1 1 0 0

Step 1: Process 4-cell groups

Since m=3 and n=4, we iterate through i ∈ [0,1) and j ∈ [0,2).

For position (0, 0):

  • The 4 symmetric cells are: (0,0), (0,3), (2,0), (2,3)
  • Their values: 1, 1, 1, 0
  • Count of 1s: 3
  • To make them all equal: min(3, 4-3) = 1 flip needed
  • We flip (2,3) from 0β†’1 to make all four cells equal to 1

For position (0, 1):

  • The 4 symmetric cells are: (0,1), (0,2), (2,1), (2,2)
  • Their values: 0, 0, 1, 0
  • Count of 1s: 1
  • To make them all equal: min(1, 4-1) = 1 flip needed
  • We flip (2,1) from 1β†’0 to make all four cells equal to 0

After Step 1, our grid becomes:

1 0 0 1
0 1 1 0  (middle row - unchanged so far)
1 0 0 1

Total flips so far: 2

Step 2: Check center cell

Since m=3 (odd) but n=4 (even), there's no single center cell. Skip this step.

Step 3: Handle middle row

Since m=3 is odd, we have a middle row at index 1. We check pairs:

  • Pair (1,0) and (1,3): values are 0 and 0 β†’ they match

    • cnt1 += 0Γ—2 = 0
  • Pair (1,1) and (1,2): values are 1 and 1 β†’ they match

    • cnt1 += 1Γ—2 = 2

So diff = 0 (no differing pairs) and cnt1 = 2

Step 4: Determine additional flips

We have cnt1 = 2, which means cnt1 % 4 = 2 (not divisible by 4).

Since cnt1 % 4 β‰  0 and diff = 0, we need 2 additional flips. We must flip one matching pair to fix the divisibility issue. Let's flip the pair (1,1) and (1,2) from 1β†’0:

Final grid:

1 0 0 1
0 0 0 0
1 0 0 1

Let's verify:

  • All rows are palindromic: βœ“
  • All columns are palindromic: βœ“
  • Total 1s: 4 (divisible by 4) βœ“

Total minimum flips: 2 + 2 = 4

This example demonstrates how the algorithm:

  1. First handles groups of 4 symmetric cells
  2. Then addresses the middle row/column palindrome constraints
  3. Finally ensures the total count of 1s is divisible by 4

Solution Implementation

1class Solution:
2    def minFlips(self, grid: List[List[int]]) -> int:
3        rows, cols = len(grid), len(grid[0])
4        total_flips = 0
5      
6        # Process each group of 4 symmetric cells (corners of rectangles)
7        for row in range(rows // 2):
8            for col in range(cols // 2):
9                # Find the symmetric positions
10                sym_row = rows - row - 1
11                sym_col = cols - col - 1
12              
13                # Count ones in the group of 4 symmetric cells
14                ones_count = (grid[row][col] + 
15                             grid[sym_row][col] + 
16                             grid[row][sym_col] + 
17                             grid[sym_row][sym_col])
18              
19                # Minimum flips needed to make all 4 cells equal
20                # Either make all 0s or all 1s, whichever requires fewer flips
21                total_flips += min(ones_count, 4 - ones_count)
22      
23        # Handle center cell if both dimensions are odd
24        if rows % 2 == 1 and cols % 2 == 1:
25            total_flips += grid[rows // 2][cols // 2]
26      
27        # Handle middle row and column for palindrome property
28        mismatched_pairs = 0
29        paired_ones_count = 0
30      
31        # Process middle row if grid has odd number of rows
32        if rows % 2 == 1:
33            for col in range(cols // 2):
34                left_val = grid[rows // 2][col]
35                right_val = grid[rows // 2][cols - col - 1]
36              
37                if left_val == right_val:
38                    # Count paired ones (both cells are 1)
39                    paired_ones_count += left_val * 2
40                else:
41                    # Count mismatched pairs
42                    mismatched_pairs += 1
43      
44        # Process middle column if grid has odd number of columns
45        if cols % 2 == 1:
46            for row in range(rows // 2):
47                top_val = grid[row][cols // 2]
48                bottom_val = grid[rows - row - 1][cols // 2]
49              
50                if top_val == bottom_val:
51                    # Count paired ones (both cells are 1)
52                    paired_ones_count += top_val * 2
53                else:
54                    # Count mismatched pairs
55                    mismatched_pairs += 1
56      
57        # Adjust flips based on divisibility by 4 requirement
58        # If paired ones are divisible by 4 or we have mismatched pairs, 
59        # add the mismatched pairs count; otherwise add 2
60        if paired_ones_count % 4 == 0 or mismatched_pairs > 0:
61            total_flips += mismatched_pairs
62        else:
63            total_flips += 2
64      
65        return total_flips
66
1class Solution {
2    public int minFlips(int[][] grid) {
3        int rows = grid.length;
4        int cols = grid[0].length;
5        int totalFlips = 0;
6      
7        // Process the 4-symmetric quadrants (corners that mirror across both axes)
8        for (int i = 0; i < rows / 2; i++) {
9            for (int j = 0; j < cols / 2; j++) {
10                // Calculate positions of the 4 symmetric cells
11                int mirrorRow = rows - i - 1;
12                int mirrorCol = cols - j - 1;
13              
14                // Count number of 1s among the 4 symmetric positions
15                int onesCount = grid[i][j] + grid[mirrorRow][j] + 
16                               grid[i][mirrorCol] + grid[mirrorRow][mirrorCol];
17              
18                // Choose minimum flips: either flip all 1s to 0 or all 0s to 1
19                totalFlips += Math.min(onesCount, 4 - onesCount);
20            }
21        }
22      
23        // Handle the center cell if both dimensions are odd
24        if (rows % 2 == 1 && cols % 2 == 1) {
25            // Center cell must be 0 for palindrome property
26            totalFlips += grid[rows / 2][cols / 2];
27        }
28      
29        int mismatchCount = 0;  // Count of mismatched pairs in middle row/column
30        int pairedOnesCount = 0; // Count of 1s in matched pairs
31      
32        // Process middle row if number of rows is odd
33        if (rows % 2 == 1) {
34            int middleRow = rows / 2;
35            for (int j = 0; j < cols / 2; j++) {
36                int mirrorCol = cols - j - 1;
37              
38                if (grid[middleRow][j] == grid[middleRow][mirrorCol]) {
39                    // If pair matches and both are 1s, add 2 to count
40                    pairedOnesCount += grid[middleRow][j] * 2;
41                } else {
42                    // Pair doesn't match, needs one flip
43                    mismatchCount++;
44                }
45            }
46        }
47      
48        // Process middle column if number of columns is odd
49        if (cols % 2 == 1) {
50            int middleCol = cols / 2;
51            for (int i = 0; i < rows / 2; i++) {
52                int mirrorRow = rows - i - 1;
53              
54                if (grid[i][middleCol] == grid[mirrorRow][middleCol]) {
55                    // If pair matches and both are 1s, add 2 to count
56                    pairedOnesCount += grid[i][middleCol] * 2;
57                } else {
58                    // Pair doesn't match, needs one flip
59                    mismatchCount++;
60                }
61            }
62        }
63      
64        // Adjust flips based on divisibility by 4 constraint
65        // If pairedOnesCount is divisible by 4 or we have mismatches, use mismatchCount
66        // Otherwise, we need 2 additional flips to maintain divisibility
67        totalFlips += (pairedOnesCount % 4 == 0 || mismatchCount > 0) ? mismatchCount : 2;
68      
69        return totalFlips;
70    }
71}
72
1class Solution {
2public:
3    int minFlips(vector<vector<int>>& grid) {
4        int rows = grid.size();
5        int cols = grid[0].size();
6        int totalFlips = 0;
7      
8        // Process all 4-symmetric groups (corners that must be equal)
9        // Each group consists of 4 cells: (i,j), (i,n-1-j), (m-1-i,j), (m-1-i,n-1-j)
10        for (int i = 0; i < rows / 2; ++i) {
11            for (int j = 0; j < cols / 2; ++j) {
12                int mirrorRow = rows - i - 1;
13                int mirrorCol = cols - j - 1;
14              
15                // Count number of 1s in the 4-cell group
16                int onesCount = grid[i][j] + grid[mirrorRow][j] + 
17                               grid[i][mirrorCol] + grid[mirrorRow][mirrorCol];
18              
19                // Choose minimum flips: either make all 0s or all 1s
20                totalFlips += min(onesCount, 4 - onesCount);
21            }
22        }
23      
24        // Handle center cell if both dimensions are odd
25        if (rows % 2 == 1 && cols % 2 == 1) {
26            // Center cell must be 0 for palindrome property
27            totalFlips += grid[rows / 2][cols / 2];
28        }
29      
30        int mismatchPairs = 0;  // Count of mismatched symmetric pairs
31        int matchedOnes = 0;     // Count of 1s in matched symmetric pairs
32      
33        // Process middle row if number of rows is odd
34        if (rows % 2 == 1) {
35            int middleRow = rows / 2;
36            for (int j = 0; j < cols / 2; ++j) {
37                int mirrorCol = cols - j - 1;
38              
39                if (grid[middleRow][j] == grid[middleRow][mirrorCol]) {
40                    // If pair matches and both are 1s, count them
41                    matchedOnes += grid[middleRow][j] * 2;
42                } else {
43                    // Count mismatched pairs
44                    mismatchPairs += 1;
45                }
46            }
47        }
48      
49        // Process middle column if number of columns is odd
50        if (cols % 2 == 1) {
51            int middleCol = cols / 2;
52            for (int i = 0; i < rows / 2; ++i) {
53                int mirrorRow = rows - i - 1;
54              
55                if (grid[i][middleCol] == grid[mirrorRow][middleCol]) {
56                    // If pair matches and both are 1s, count them
57                    matchedOnes += grid[i][middleCol] * 2;
58                } else {
59                    // Count mismatched pairs
60                    mismatchPairs += 1;
61                }
62            }
63        }
64      
65        // Handle the special case for middle row/column
66        // If matchedOnes is not divisible by 4 and no mismatched pairs exist,
67        // we need to flip 2 matched 1s to maintain divisibility by 4
68        totalFlips += (matchedOnes % 4 == 0 || mismatchPairs > 0) ? mismatchPairs : 2;
69      
70        return totalFlips;
71    }
72};
73
1/**
2 * Calculates minimum flips needed to make a grid palindromic in both directions
3 * with the number of 1s divisible by 4
4 * @param grid - 2D binary grid
5 * @returns minimum number of flips required
6 */
7function minFlips(grid: number[][]): number {
8    const rows: number = grid.length;
9    const cols: number = grid[0].length;
10    let totalFlips: number = 0;
11
12    // Process each quadrant (4 symmetric positions)
13    // For positions that mirror across both axes
14    for (let row = 0; row < Math.floor(rows / 2); row++) {
15        for (let col = 0; col < Math.floor(cols / 2); col++) {
16            // Calculate symmetric positions
17            const mirrorRow: number = rows - row - 1;
18            const mirrorCol: number = cols - col - 1;
19          
20            // Count number of 1s in the four symmetric positions
21            const onesCount: number = grid[row][col] + grid[mirrorRow][col] + 
22                                      grid[row][mirrorCol] + grid[mirrorRow][mirrorCol];
23          
24            // Choose minimum flips: either make all 0s or all 1s
25            totalFlips += Math.min(onesCount, 4 - onesCount);
26        }
27    }
28
29    // Handle center cell if both dimensions are odd
30    if (rows % 2 === 1 && cols % 2 === 1) {
31        // Center cell must be 0 for divisibility by 4
32        totalFlips += grid[Math.floor(rows / 2)][Math.floor(cols / 2)];
33    }
34
35    let mismatchPairs: number = 0;  // Count of mismatched symmetric pairs
36    let matchedOnes: number = 0;     // Count of 1s in matched pairs
37
38    // Process middle row if grid has odd number of rows
39    if (rows % 2 === 1) {
40        const middleRow: number = Math.floor(rows / 2);
41      
42        for (let col = 0; col < Math.floor(cols / 2); col++) {
43            const mirrorCol: number = cols - col - 1;
44          
45            if (grid[middleRow][col] === grid[middleRow][mirrorCol]) {
46                // If pair matches, count the 1s (multiply by 2 for both positions)
47                matchedOnes += grid[middleRow][col] * 2;
48            } else {
49                // If pair doesn't match, we need to flip one
50                mismatchPairs += 1;
51            }
52        }
53    }
54
55    // Process middle column if grid has odd number of columns
56    if (cols % 2 === 1) {
57        const middleCol: number = Math.floor(cols / 2);
58      
59        for (let row = 0; row < Math.floor(rows / 2); row++) {
60            const mirrorRow: number = rows - row - 1;
61          
62            if (grid[row][middleCol] === grid[mirrorRow][middleCol]) {
63                // If pair matches, count the 1s (multiply by 2 for both positions)
64                matchedOnes += grid[row][middleCol] * 2;
65            } else {
66                // If pair doesn't match, we need to flip one
67                mismatchPairs += 1;
68            }
69        }
70    }
71
72    // Adjust flips to ensure total 1s is divisible by 4
73    // If matched 1s already divisible by 4 or we have mismatches to fix, use mismatch count
74    // Otherwise, need to flip 2 more matched 1s to 0s
75    totalFlips += (matchedOnes % 4 === 0 || mismatchPairs > 0) ? mismatchPairs : 2;
76  
77    return totalFlips;
78}
79

Time and Space Complexity

Time Complexity: O(m Γ— n)

The algorithm iterates through the grid in the following manner:

  • The first nested loop iterates through (m // 2) Γ— (n // 2) elements, processing each quadrant's corresponding four cells, which takes O(m Γ— n / 4) time.
  • If m is odd, it processes the middle row with n // 2 iterations, taking O(n / 2) time.
  • If n is odd, it processes the middle column with m // 2 iterations, taking O(m / 2) time.
  • The center cell (if both m and n are odd) is processed in O(1) time.

The total time is O(m Γ— n / 4) + O(n / 2) + O(m / 2) + O(1), which simplifies to O(m Γ— n) since we visit each cell of the grid at most once.

Space Complexity: O(1)

The algorithm uses only a constant amount of extra space with variables ans, i, j, x, y, cnt1, and diff. No additional data structures that scale with input size are created, resulting in constant space complexity.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Incorrectly Handling the Middle Row/Column Palindrome Requirement

Pitfall: A common mistake is forgetting that when processing middle rows or columns, we need to ensure they are palindromic while also maintaining the divisibility by 4 constraint. Many solutions incorrectly assume that simply making pairs match is sufficient.

Example of the mistake:

# WRONG: Just counting flips to make pairs match
if rows % 2 == 1:
    for col in range(cols // 2):
        if grid[rows // 2][col] != grid[rows // 2][cols - col - 1]:
            total_flips += 1  # This ignores the divisibility constraint!

Solution: Track both mismatched pairs AND the count of 1s from matched pairs. This allows us to make intelligent decisions about whether to flip pairs to 0s or 1s to satisfy the divisibility by 4 requirement.

2. Misunderstanding the Center Cell Logic

Pitfall: When both dimensions are odd, the center cell must always be 0 for the total count to be divisible by 4. A common error is trying to include this cell in complex calculations or forgetting about it entirely.

Example of the mistake:

# WRONG: Trying to be clever with the center cell
if rows % 2 and cols % 2:
    center = grid[rows // 2][cols // 2]
    if (total_ones + center) % 4 != 0:  # Overcomplicated and wrong!
        total_flips += 1

Solution: Simply check if the center cell is 1. If it is, flip it to 0. The logic is straightforward: total_flips += grid[rows // 2][cols // 2]

3. Off-by-One Errors in Symmetric Position Calculations

Pitfall: Calculating symmetric positions incorrectly, especially when dealing with 0-indexed arrays.

Example of the mistake:

# WRONG: Incorrect symmetric position
sym_row = rows - row  # Should be rows - row - 1
sym_col = cols - col  # Should be cols - col - 1

Solution: Always use rows - row - 1 and cols - col - 1 for finding symmetric positions in 0-indexed arrays. Test with small examples to verify correctness.

4. Incorrect Final Adjustment Logic

Pitfall: The final adjustment for divisibility by 4 is subtle. The condition paired_ones_count % 4 == 0 or mismatched_pairs > 0 might seem arbitrary but is crucial.

Example of the mistake:

# WRONG: Always adding mismatched_pairs
total_flips += mismatched_pairs  # Doesn't handle the case when we need to flip a matched pair

Solution: Understand the two cases:

  • If paired_ones_count % 4 == 2 and mismatched_pairs == 0: We must flip one matched pair (2 flips)
  • Otherwise: We can fix mismatched pairs to adjust the count (mismatched_pairs flips)

5. Double-Counting Cells in Groups

Pitfall: When processing the 4-cell groups, middle rows, and middle columns, ensure cells aren't processed multiple times.

Example of the mistake:

# WRONG: Processing all rows and columns without considering overlap
for row in range(rows):  # Should be range(rows // 2)
    for col in range(cols):  # Should be range(cols // 2)

Solution: Use range(rows // 2) and range(cols // 2) for the 4-cell groups, and carefully handle middle rows/columns separately to avoid overlap.

Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

A heap is a ...?


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More