[M模拟] lc3240. 最少翻转次数使二进制矩阵回文 II(分类讨论+遍历技巧+代码实现+双周赛136_3)

1. 题目来源

链接:3240. 最少翻转次数使二进制矩阵回文 II

2. 题目解析

这个题目挺好的,考验的是代码实现能力。

对于 n/2、m/2 这个区域里面的点肯定有回文的 右、下、右下 这三个点。直观来看,要么都是 0,要么都是 1。所以这些点是不影响是否被 4 整除的。

但是这样的话,我们是没有考虑对称轴 n/2 这一行,m/2 这一列的,根本遍历不到…所以需要单独考虑下:

对于单行、单列,与其对应的回文点只有一个。

  • 如果它本来是相等的且还都是1:那么合计贡献一个 2,统计一下这样的 1 有多少个。因为如果这样的 2 是奇数个的话,将无法被 4 整除。记为 one。
  • 如果两者不相等的话,则需要操作一次,使之相等。这里我们将其变为 0、0, 1、1 都是可以的。累计一下这样的情况有多少个,记为 cnt。

操作次数累加上这些 cnt。

如果 cnt 为 0,说明大家都是想等的,但是 one 却是奇数的话,说明我们需要将两个 1、1 变为 0、0,使其能被 4 整除。

对于中心点来看,3*3 棋盘,【1,1】点不会被我们遍历到,那么如果要被 4 整除,【1,1】 这类点一定需要为 0,所以最终累计下【1,1】是否需要操作即可。

挺好的分类讨论,一旦设计到回文的话,很容易会漏掉 n/2、m/2 这种边界情况。如果强行嵌入到代码里面也不是不行,比赛的时候是这样想的…但情况一多就比较难去控制…还不如抽象出来,单独写逻辑。


  • 时间复杂度 O ( n ∗ m ) O(n*m) O(nm)
  • 空间复杂度 O ( 1 ) O(1) O(1)

class Solution {
public:
    int minFlips(vector<vector<int>>& grid) {
        int n = grid.size(), m = grid[0].size();
        int res = 0;  // 操作次数

        // 统计
        for (int i = 0; i < n / 2; i ++ ) {
            for (int j = 0; j < m / 2; j ++ ) {
                int a = grid[i][j], b = grid[i][m - j - 1];
                int c = grid[n - i - 1][j], d = grid[n - i - 1][m - j -  1];
                int s = a + b + c + d;
                res += min(4 - s, s);
            }
        }

        int cnt = 0, one = 0;
        if (n & 1) {
            for (int j = 0; j < m / 2; j ++ ) {
                int a = grid[n / 2][j], b = grid[n / 2][m - j - 1];
                if (a == b && a == 1) one ++ ;
                else if (a != b) cnt ++ ;
            }
        }

        if (m & 1) {
            for (int i = 0; i < n / 2; i ++ ) {
                int a = grid[i][m / 2], b = grid[n - i - 1][m / 2];
                if (a == b && a == 1) one ++ ;
                else if (a != b) cnt ++ ;
            }
        }

        res += cnt;
        if (cnt == 0 && one % 2 == 1) res += 2;
        if (n & 1 && m & 1) res += grid[n / 2][m / 2] == 1;

        return res;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Ypuyu

如果帮助到你,可以请作者喝水~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值