翻转矩阵后的得分

标签: 贪心 位运算 数组 矩阵

难度: Medium

给你一个大小为 m x n 的二元矩阵 grid ,矩阵中每个元素的值为 01

一次 移动 是指选择任一行或列,并转换该行或列中的每一个值:将所有 0 都更改为 1,将所有 1 都更改为 0

在做出任意次数的移动后,将该矩阵的每一行都按照二进制数来解释,矩阵的 得分 就是这些数字的总和。

在执行任意次 移动 后(含 0 次),返回可能的最高分数。

示例 1:

输入:grid = [[0,0,1,1],[1,0,1,0],[1,1,0,0]]
输出:39
解释:0b1111 + 0b1001 + 0b1111 = 15 + 9 + 15 = 39

示例 2:

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

提示:

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 20
  • grid[i][j]01

Submission

运行时间: 24 ms

内存: 16.6 MB

class Solution:
    def matrixScore(self, grid: List[List[int]]) -> int:
        row, col = len(grid), len(grid[0])

        for r in range(row):
            if grid[r][0] == 0:
                grid[r] = list(map(lambda x: 1 - x, grid[r]))

        ans = 0
        base = 1
        for c in range(col-1, -1, -1):
            cnt = 0
            for r in range(0, row):
                if grid[r][c] == 1:
                    cnt += 1
            cnt = max(cnt, row-cnt)
            ans += base * cnt
            base *= 2

        return ans

Explain

题解的主要思路是首先确保每行的第一个数字为1,以使得该行的二进制数值最大化。这是通过翻转所有第一个元素为0的行实现的。然后,对于每一列,计算有多少行的该列元素是1,并决定是否需要翻转整列以使得更多的1出现在该列上,从而最大化整个矩阵的分数。为每列计算分数时,基于该列对应的二进制权重累加得分。

时间复杂度: O(m * n)

空间复杂度: O(1)

class Solution:
    def matrixScore(self, grid: List[List[int]]) -> int:
        row, col = len(grid), len(grid[0])

        # 翻转所有第一个元素为0的行,以确保每行以1开始
        for r in range(row):
            if grid[r][0] == 0:
                grid[r] = list(map(lambda x: 1 - x, grid[r]))

        ans = 0
        base = 1
        # 从最低位到最高位计算每列的贡献
        for c in range(col-1, -1, -1):
            cnt = 0
            # 计算当前列中1的数量
            for r in range(0, row):
                if grid[r][c] == 1:
                    cnt += 1
            # 确定是否需要翻转列以最大化1的数量
            cnt = max(cnt, row-cnt)
            # 计算当前列的贡献
            ans += base * cnt
            base *= 2

        return ans

Explore

在此问题的上下文中,确保每行的第一个数字为1总是会最大化该行的值。这是因为在二进制数中,最左边的数位(即最高位)对总值的影响最大。例如,1000在二进制中比0111要大,尽管0111的1比1000多。因此,将每行的第一个元素设置为1后,该行的值将是可能的最大值。

决定是否翻转某一列是基于最大化该列中1的数量的原则。具体地,如果一列中0的数量多于1的数量,则翻转这一列将使得更多的1出现在该列中。这是因为在二进制表示中,每一列都对应一个权重(即2的幂),列中的每一个1都会按该权重增加总分。因此,通过比较一列中1的数量与0的数量来决定是否翻转,以确保每列贡献的分数最大化。

使用`map(lambda x: 1 - x, grid[r])`进行行翻转的优势在于简洁和表达直观,特别是对于Python开发者来说,代码易于理解。然而,这种方法在性能上可能不如直接遍历数组修改或使用列表推导式,因为它涉及到额外的函数调用开销。列表推导式或直接修改可能会更快,因为它们可以直接在原地进行操作,减少了函数调用和对象创建的开销。