Medium
题目描述
给你一个大小为 m x n 的二进制矩阵 grid 。
一次 移动 就是选择任一行或者列,并转换该行或者列中的每一个值:将所有 0 都更改为 1,将所有 1 都更改为 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.lengthn == grid[i].length1 <= m, n <= 20grid[i][j]不是0就是1
解题思路
这是一道贪心算法题目,关键在于理解二进制数的权重分布。
核心思路:
最高位优先原则:在二进制表示中,最高位(最左边)的权重最大。对于 n 位二进制数,最高位的权重是 2^(n-1),而其他所有位的权重之和最多为 2^(n-1)-1。因此,保证最高位为 1 比其他位都重要。
贪心策略:
- 第一步:确保每一行的最高位都是 1。如果某行最高位是 0,就翻转这一行
- 第二步:对于每一列(从第二列开始),统计该列中 1 的个数。如果 0 的个数多于 1 的个数,就翻转这一列
为什么这样是最优的:
- 翻转行操作不会影响列之间的相对关系,所以先处理行是安全的
- 在保证最高位全为 1 的前提下,每一列独立地选择翻转与否,使得该列的 1 尽可能多
- 由于二进制的权重特性,高位的 1 比低位更重要,所以按列从左到右贪心处理是最优的
算法步骤:
- 遍历每一行,如果第一位是 0,翻转整行
- 遍历每一列(从第二列开始),统计该列 1 的个数,如果少于一半就翻转该列
- 计算最终得分
代码实现
class Solution {
public:
int matrixScore(vector<vector<int>>& grid) {
int m = grid.size(), n = grid[0].size();
// 确保每行最高位为1
for (int i = 0; i < m; i++) {
if (grid[i][0] == 0) {
for (int j = 0; j < n; j++) {
grid[i][j] = 1 - grid[i][j];
}
}
}
// 对每列进行优化
for (int j = 1; j < n; j++) {
int count1 = 0;
for (int i = 0; i < m; i++) {
count1 += grid[i][j];
}
// 如果0的个数多于1的个数,翻转该列
if (count1 < m - count1) {
for (int i = 0; i < m; i++) {
grid[i][j] = 1 - grid[i][j];
}
}
}
// 计算最终得分
int result = 0;
for (int i = 0; i < m; i++) {
int rowValue = 0;
for (int j = 0; j < n; j++) {
rowValue = rowValue * 2 + grid[i][j];
}
result += rowValue;
}
return result;
}
};
class Solution:
def matrixScore(self, grid: List[List[int]]) -> int:
m, n = len(grid), len(grid[0])
# 确保每行最高位为1
for i in range(m):
if grid[i][0] == 0:
for j in range(n):
grid[i][j] = 1 - grid[i][j]
# 对每列进行优化
for j in range(1, n):
count1 = sum(grid[i][j] for i in range(m))
# 如果0的个数多于1的个数,翻转该列
if count1 < m - count1:
for i in range(m):
grid[i][j] = 1 - grid[i][j]
# 计算最终得分
result = 0
for i in range(m):
row_value = 0
for j in range(n):
row_value = row_value * 2 + grid[i][j]
result += row_value
return result
public class Solution {
public int MatrixScore(int[][] grid) {
int m = grid.Length, n = grid[0].Length;
// 确保每行最高位为1
for (int i = 0; i < m; i++) {
if (grid[i][0] == 0) {
for (int j = 0; j < n; j++) {
grid[i][j] = 1 - grid[i][j];
}
}
}
// 对每列进行优化
for (int j = 1; j < n; j++) {
int count1 = 0;
for (int i = 0; i < m; i++) {
count1 += grid[i][j];
}
// 如果0的个数多于1的个数,翻转该列
if (count1 < m - count1) {
for (int i = 0; i < m; i++) {
grid[i][j] = 1 - grid[i][j];
}
}
}
// 计算最终得分
int result = 0;
for (int i = 0; i < m; i++) {
int rowValue = 0;
for (int j = 0; j < n; j++) {
rowValue = rowValue * 2 + grid[i][j];
}
result += rowValue;
}
return result;
}
}
var matrixScore = function(grid) {
const m = grid.length, n = grid[0].length;
// 确保每行最高位为1
for (let i = 0; i < m; i++) {
if (grid[i][0]
复杂度分析
| 复杂度类型 | 复杂度 | 说明 |
|---|---|---|
| 时间复杂度 | O(m × n) | 需要遍历矩阵常数次,每次都是 O(m × n) |
| 空间复杂度 | O(1) | 只使用了常数个额外变量,原地修改矩阵 |