Medium

题目描述

给你一个 m x n 的二进制矩阵 grid

如果一行或一列的值从前往后读和从后往前读是相同的,则认为该行或列是回文的。

你可以将 grid 中任意数量的格子从 0 翻转为 1,或从 1 翻转为 0

返回使所有行和列都成为回文,且 grid1 的总数能被 4 整除所需的最少翻转次数。

示例 1:

输入:grid = [[1,0,0],[0,1,0],[0,0,1]]
输出:3

示例 2:

输入:grid = [[0,1],[0,1],[0,0]]
输出:2

示例 3:

输入:grid = [[1],[1]]
输出:2

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m * n <= 2 * 10^5
  • 0 <= grid[i][j] <= 1

解题思路

解题思路

这道题要求我们同时满足两个条件:

  1. 所有行和列都是回文的
  2. 网格中 1 的总数能被 4 整除

核心观察: 要使矩阵既行回文又列回文,那么对于位置 (i,j),它必须与以下三个位置的值相同:

  • (i, n-1-j) - 行回文对称位置
  • (m-1-i, j) - 列回文对称位置
  • (m-1-i, n-1-j) - 对角对称位置

这意味着这四个位置构成一个等价组,它们的值必须相同。

解题步骤:

  1. 处理四元素组: 遍历矩阵的前半部分,将每四个对称位置归为一组。对于每组,计算翻转成全 0 或全 1 的最小代价,选择代价较小的方案。

  2. 处理中心行/列: 如果行数或列数为奇数,需要特殊处理中心行/列。中心行/列上的对称位置对必须相同,且为了满足 1 的总数被 4 整除,需要仔细计算。

  3. 调整总数: 最后检查 1 的总数是否被 4 整除,如果不是则需要额外翻转。

关键在于正确处理边界情况和中心元素,确保既满足回文要求又满足总数要求。

代码实现

class Solution {
public:
    int minFlips(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        int flips = 0;
        int ones = 0;
        
        // Handle 4-element groups (corners and symmetric positions)
        for (int i = 0; i < (m + 1) / 2; i++) {
            for (int j = 0; j < (n + 1) / 2; j++) {
                if (i == m - 1 - i && j == n - 1 - j) {
                    // Center element (only exists when both m and n are odd)
                    continue;
                }
                
                vector<int> positions;
                positions.push_back(grid[i][j]);
                if (j != n - 1 - j) positions.push_back(grid[i][n - 1 - j]);
                if (i != m - 1 - i) positions.push_back(grid[m - 1 - i][j]);
                if (i != m - 1 - i && j != n - 1 - j) positions.push_back(grid[m - 1 - i][n - 1 - j]);
                
                int count1 = 0;
                for (int val : positions) {
                    if (val == 1) count1++;
                }
                
                // Choose to make all 0s or all 1s, whichever costs less
                int cost0 = count1;
                int cost1 = positions.size() - count1;
                
                if (cost0 <= cost1) {
                    flips += cost0;
                } else {
                    flips += cost1;
                    ones += positions.size();
                }
            }
        }
        
        // Handle middle row if m is odd
        if (m % 2 == 1) {
            int mid_row = m / 2;
            int pairs1 = 0, single_pairs = 0;
            
            for (int j = 0; j < n / 2; j++) {
                if (grid[mid_row][j] != grid[mid_row][n - 1 - j]) {
                    flips++;
                    single_pairs++;
                } else if (grid[mid_row][j] == 1) {
                    pairs1++;
                }
            }
            ones += pairs1 * 2;
        }
        
        // Handle middle column if n is odd
        if (n % 2 == 1) {
            int mid_col = n / 2;
            int pairs1 = 0, single_pairs = 0;
            
            for (int i = 0; i < m / 2; i++) {
                if (grid[i][mid_col] != grid[m - 1 - i][mid_col]) {
                    flips++;
                    single_pairs++;
                } else if (grid[i][mid_col] == 1) {
                    pairs1++;
                }
            }
            ones += pairs1 * 2;
        }
        
        // Handle center element if both m and n are odd
        if (m % 2 == 1 && n % 2 == 1) {
            if (grid[m / 2][n / 2] == 1) {
                flips++;
            }
        }
        
        // Ensure total 1s is divisible by 4
        if (ones % 4 != 0) {
            flips += 2;
        }
        
        return flips;
    }
};
class Solution:
    def minFlips(self, grid: List[List[int]]) -> int:
        m, n = len(grid), len(grid[0])
        flips = 0
        ones = 0
        
        # Handle 4-element groups (corners and symmetric positions)
        for i in range((m + 1) // 2):
            for j in range((n + 1) // 2):
                if i == m - 1 - i and j == n - 1 - j:
                    # Center element (only exists when both m and n are odd)
                    continue
                
                positions = []
                positions.append(grid[i][j])
                if j != n - 1 - j:
                    positions.append(grid[i][n - 1 - j])
                if i != m - 1 - i:
                    positions.append(grid[m - 1 - i][j])
                if i != m - 1 - i and j != n - 1 - j:
                    positions.append(grid[m - 1 - i][n - 1 - j])
                
                count1 = sum(positions)
                
                # Choose to make all 0s or all 1s, whichever costs less
                cost0 = count1
                cost1 = len(positions) - count1
                
                if cost0 <= cost1:
                    flips += cost0
                else:
                    flips += cost1
                    ones += len(positions)
        
        # Handle middle row if m is odd
        if m % 2 == 1:
            mid_row = m // 2
            pairs1 = 0
            
            for j in range(n // 2):
                if grid[mid_row][j] != grid[mid_row][n - 1 - j]:
                    flips += 1
                elif grid[mid_row][j] == 1:
                    pairs1 += 1
            ones += pairs1 * 2
        
        # Handle middle column if n is odd
        if n % 2 == 1:
            mid_col = n // 2
            pairs1 = 0
            
            for i in range(m // 2):
                if grid[i][mid_col] != grid[m - 1 - i][mid_col]:
                    flips += 1
                elif grid[i][mid_col] == 1:
                    pairs1 += 1
            ones += pairs1 * 2
        
        # Handle center element if both m and n are odd
        if m % 2 == 1 and n % 2 == 1:
            if grid[m // 2][n // 2] == 1:
                flips += 1
        
        # Ensure total 1s is divisible by 4
        if ones % 4 != 0:
            flips += 2
        
        return flips
public class Solution {
    public int MinFlips(int[][] grid) {
        int m = grid.Length, n = grid[0].Length;
        int flips = 0;
        int ones = 0;
        
        // Handle 4-element groups (corners and symmetric positions)
        for (int i = 0; i < (m + 1) / 2; i++) {
            for (int j = 0; j < (n + 1) / 2; j++) {
                if (i == m - 1 - i && j == n - 1 - j) {
                    // Center element (only exists when both m and n are odd)
                    continue;
                }
                
                List<int> positions = new List<int>();
                positions.Add(grid[i][j]);
                if (j != n - 1 - j) positions.Add(grid[i][n - 1 - j]);
                if (i != m - 1 - i) positions.Add(grid[m - 1 - i][j]);
                if (i != m - 1 - i && j != n - 1 - j) positions.Add(grid[m - 1 - i][n - 1 - j]);
                
                int count1 = 0;
                foreach (int val in positions) {
                    if (val == 1) count1++;
                }
                
                // Choose to make all 0s or all 1s, whichever costs less
                int cost0 = count1;
                int cost1 = positions.Count - count1;
                
                if (cost0 <= cost1) {
                    flips += cost0;
                } else {
                    flips += cost1;
                    ones += positions.Count;
                }
            }
        }
        
        // Handle middle row if m is odd
        if (m % 2 == 1) {
            int midRow = m / 2;
            int pairs1 = 0;
            
            for (int j = 0; j < n / 2; j++) {
                if (grid[midRow][j] != grid[midRow][n - 1 - j]) {
                    flips++;
                } else if (grid[midRow][j] == 1) {
                    pairs1++;
                }
            }
            ones += pairs1 * 2;
        }
        
        // Handle middle column if n is odd
        if (n % 2 == 1) {
            int midCol = n / 2;
            int pairs1 = 0;
            
            for (int i = 0; i < m / 2; i++) {
                if (grid[i][midCol] != grid[m - 1 - i][midCol]) {
                    flips++;
                } else if (grid[i][midCol] == 1) {
                    pairs1++;
                }
            }
            ones += pairs1 * 2;
        }
        
        // Handle center element if both m and n are odd
        if (m % 2 == 1 && n % 2 == 1) {
            if (grid[m / 2][n / 2] == 1) {
                flips++;
            }
        }
        
        // Ensure total 1s is divisible by 4
        if (ones % 4 != 0) {
            flips += 2;
        }
        
        return flips;
    }
}
var minFlips = function(grid) {
    const m = grid.length;
    const n = grid[0].length;
    let flips = 0;
    
    // Handle corner cases for odd dimensions
    const midRow = Math.floor(m / 2);
    const midCol = Math.floor(n / 2);
    
    // Process symmetric pairs (excluding middle row/col if odd)
    for (let i = 0; i < midRow; i++) {
        for (let j = 0; j < midCol; j++) {
            const cells = [
                grid[i][j],
                grid[i][n - 1 - j],
                grid[m - 1 - i][j],
                grid[m - 1 - i][n - 1 - j]
            ];
            const ones = cells.reduce((sum, val) => sum + val, 0);
            flips += Math.min(ones, 4 - ones);
        }
    }
    
    let extraOnes = 0;
    let pairs = 0;
    
    // Handle middle row if m is odd
    if (m % 2 === 1) {
        for (let j = 0; j < midCol; j++) {
            if (grid[midRow][j] !== grid[midRow][n - 1 - j]) {
                flips++;
            } else if (grid[midRow][j] === 1) {
                pairs++;
            }
        }
    }
    
    // Handle middle column if n is odd
    if (n % 2 === 1) {
        for (let i = 0; i < midRow; i++) {
            if (grid[i][midCol] !== grid[m - 1 - i][midCol]) {
                flips++;
            } else if (grid[i][midCol] === 1) {
                pairs++;
            }
        }
    }
    
    // Handle center cell if both m and n are odd
    if (m % 2 === 1 && n % 2 === 1) {
        if (grid[midRow][midCol] === 1) {
            flips++;
        }
    }
    
    // If we have odd number of pair-ones, we need to flip one pair
    if (pairs % 2 === 1) {
        flips += 2;
    }
    
    return flips;
};

复杂度分析

指标复杂度
时间-
空间-