Leetcode-861-翻转矩阵后的得分

Leetcode-861-翻转矩阵后的得分

思路:贪心算法

题目描述

  • 有一个二维矩阵 A 其中每个元素的值为 0 或 1 。

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

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

  • 返回尽可能高的分数。

1
2
3
4
5
6
7
示例:

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

算法思路

  1. 根据题意,能够知道一个重要的事实:给定一个翻转方案,则它们之间任意交换顺序后,得到的结果保持不变。因此,我们总可以先考虑所有的行翻转,再考虑所有的列翻转。
  2. 行翻转不难发现一点:为了得到最高的分数,矩阵的每一行的最左边的数都必须为1。为了做到这一点,我们可以翻转那些最左边的数不为 1 的那些行,而其他的行则保持不动。
  3. 列翻转 : 当将每一行的最左边的数都变为 1 之后,就只能进行列翻转了。
    • 为了使得总得分最大,我们要让每个列中 1 的数目尽可能多。
    • 因此,我们扫描除了最左边的列以外的每一列,如果该列 0 的数目多于 1 的数目,就翻转该列,其他的列则保持不变。

对于实际编码的时候:我们无需要修改原来的矩阵

mark

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Solution {
// 此做法不必修改原来的矩阵
public int matrixScore(int[][] A) {
int m = A.length;
int n = A[0].length;

// 1. 直接统计第一列的贡献(假设第一列全为1的结果)
int ret = m * (1 << (n - 1));

// 2. 统计从第二列开始 每一列的贡献
for(int j = 1;j < n;j++){
int nOnes = 0;
for(int i = 0; i < m;i++){
if(A[i][0] == 1){ // 说明这一行没有进行过行翻转
nOnes += A[i][j]; // 直接统计本列1的个数
}else{ // 说明这一行开头是0,需要行翻转
nOnes += (1 - A[i][j]); // 如果这一行进行了翻转,则该元素的实际取值就是 1 - A[i][j]
}
}
int k = Math.max(nOnes, m - nOnes); // k 是列翻转后1的数量 nOnes是1的数量 m - nOnes是0的数量
ret += k * (1 << (n - j - 1)); // 本列对于结果的贡献
}
return ret;
}
}

复杂度分析

  • 时间复杂度 : O(mn)
  • 空间复杂度: O(1)
打赏
  • 版权声明: 本博客所有文章除特别声明外,均采用 Apache License 2.0 许可协议。转载请注明出处!
  • © 2019-2022 Zhuuu
  • PV: UV:

请我喝杯咖啡吧~

支付宝
微信