每日一题3239.最少翻转次数使二进制矩阵回文;

本题出自LeetCode每日一题3239.最少翻转次数使二进制矩阵回文,初看想着就是一道暴力破解,双指针强硬遍历一横一竖


题目

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

如果矩阵中一行或者一列从前往后与从后往前读是一样的,那么我们称这一行或者这一列是 回文 的。

你可以将 grid 中任意格子的值 翻转 ,也就是将格子里的值从 0 变成 1 ,或者从 1 变成 0

请你返回 最少 翻转次数,使得矩阵 要么 所有行是 回文的 ,要么所有列是 回文的

示例 1:

**输入:**grid = [[1,0,0],[0,0,0],[0,0,1]]

**输出:**2

解释:

将高亮的格子翻转,得到所有行都是回文的。

示例 2:

**输入:**grid = [[0,1],[0,1],[0,0]]

**输出:**1

解释:

将高亮的格子翻转,得到所有列都是回文的。

示例 3:

**输入:**grid = [[1],[0]]

**输出:**0

解释:

所有行已经是回文的。

提示:

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

解题思路

这个问题要求我们在给定的 m x n 的二进制矩阵 grid 中,通过最少的翻转次数(即把某个位置的 0 变成 1 或者 1 变成 0),让所有的行或所有的列都成为回文。要解决这个问题,我们可以采取以下步骤:

  1. 定义回文:首先明确什么是回文。对于行来说,如果一个行从左到右读和从右到左读是一样的,那么这个行就是回文的。同样的规则适用于列。

  2. 计算翻转次数

    • 对于每一行,我们可以通过比较第 i 列和第 n-i-1 列(从左端和右端同时向中间靠拢)来检查是否需要翻转。如果这两个位置上的数字不同,则至少需要一次翻转才能使该行成为回文。
    • 同样地,对于每一列,我们可以通过比较第 i 行和第 m-i-1 行来检查是否需要翻转,以确保该列是回文的。
  3. 选择最小的翻转次数:我们需要分别计算出使所有行成为回文所需的最少翻转次数,以及使所有列成为回文所需的最少翻转次数。最终的结果应该是这两者中的较小值。


题解

c++代码

cpp 复制代码
class Solution {
public:
    int minFlips(vector<vector<int>>& grid) {
        int m = grid.size(), n = grid[0].size();
        
        auto flip = [&](int rows, int cols, bool horizontal) -> int {
            int cnt = 0;
            for (int i = 0; i < rows; ++i) {
                int l = 0, r = cols - 1;
                while (l < r) {
                    if ((horizontal && grid[i][l++] != grid[i][r--]) ||
                        (!horizontal && grid[l++][i] != grid[r--][i])) {
                        ++cnt;
                    }
                }
            }
            return cnt;
        };
        
        return min(flip(m, n, true), flip(n, m, false));
    }
};

详解

获取网格的维度

bash 复制代码
        int m = grid.size(), n = grid[0].size();
  • m 表示网格的行数。
  • n 表示网格的列数。

定义翻转操作的 lambda 函数

bash 复制代码
        auto flip = [&](int rows, int cols, bool horizontal) -> int {
            int cnt = 0;
            for (int i = 0; i < rows; ++i) {
                int l = 0, r = cols - 1;
                while (l < r) {
                    if ((horizontal && grid[i][l++] != grid[i][r--]) ||
                        (!horizontal && grid[l++][i] != grid[r--][i])) {
                        ++cnt;
                    }
                }
            }
            return cnt;
        };
  • flip 是一个 lambda 函数,用于计算需要多少次翻转才能使指定方向上的对称元素相等。
  • rowscols 分别表示要检查的行数和列数。
  • horizontal 是一个布尔变量,指示是否进行水平翻转。
  • cnt 用于计数需要翻转的次数。
  • 外层循环遍历每一行(或每一列,取决于 horizontal)。
  • 内层循环使用两个指针 lr 分别从两端向中间移动,比较对应位置的元素是否相等。如果不相等,则增加 cnt 计数器。

返回结果

bash 复制代码
        return min(flip(m, n, true), flip(n, m, false));
    }
};
  • 调用两次 flip 函数:
    • 第一次调用 flip(m, n, true) 进行水平翻转。
    • 第二次调用 flip(n, m, false) 进行垂直翻转。
  • 返回两者中较小的结果,即最少需要的翻转次数。

制作不易,您的关注与点赞是我最大的动力!

相关推荐
xiaoshiguang32 小时前
LeetCode:222.完全二叉树节点的数量
算法·leetcode
爱吃西瓜的小菜鸡2 小时前
【C语言】判断回文
c语言·学习·算法
别NULL2 小时前
机试题——疯长的草
数据结构·c++·算法
TT哇3 小时前
*【每日一题 提高题】[蓝桥杯 2022 国 A] 选素数
java·算法·蓝桥杯
yuanbenshidiaos4 小时前
C++----------函数的调用机制
java·c++·算法
唐叔在学习4 小时前
【唐叔学算法】第21天:超越比较-计数排序、桶排序与基数排序的Java实践及性能剖析
数据结构·算法·排序算法
ALISHENGYA4 小时前
全国青少年信息学奥林匹克竞赛(信奥赛)备考实战之分支结构(switch语句)
数据结构·算法
chengooooooo4 小时前
代码随想录训练营第二十七天| 贪心理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和
算法·leetcode·职场和发展
jackiendsc5 小时前
Java的垃圾回收机制介绍、工作原理、算法及分析调优
java·开发语言·算法
游是水里的游6 小时前
【算法day20】回溯:子集与全排列问题
算法