LeetCode 每日一题861. 翻转矩阵后的得分

861. 翻转矩阵后的得分

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

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

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

返回尽可能高的分数。

示例:

输入:[[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 <= A.length <= 20
  • 1 <= A[0].length <= 20
  • A[i][j] 是 0 或 1

解题思路:

「贪心算法」

根据位数越高影响越大,应该先把每一行最左边的数全部变为 1

  • 第一步是翻转那些第一个数字为 0 的行。
  • 第二步遍历每一列,第一列已经全部为 1,所以从第二列开始遍历,如果该列 0 的数量大于 1 的数量,则翻转这一列。
  • 第三步计算结果

方法一:贪心算法

按照上述步骤实现的,优化版本见下

public int matrixScore(int[][] A) {
    int rowNum = A.length;
    int cloNum = A[0].length;
    // 先找第 1 列,如果为 0 翻转这一行
    for (int i = 0; i < rowNum; i++) {
        if (A[i][0] == 0) {
            reverse(A, i , true);
        }
    }
    // 从第 2 列开始,计算该列为 0 的个数,大于一半则翻转这一列
    for (int j = 1; j < cloNum; j++) {
        int count = 0;
        for (int i = 0; i < rowNum; i++) {
            if (A[i][j] == 0) {
                count++;
            }
        }
        if (count > rowNum / 2) {
            reverse(A, j, false);
        }
    }
    // 计算结果
    int ans = 0;
    for (int i = 0; i < rowNum; i++) {
        StringBuffer sb = new StringBuffer();
        for (int j = 0; j < cloNum; j++) {
            sb.append(A[i][j]);
        }
        ans += Integer.parseInt(sb.toString(), 2);
    }
    return ans;
}
// 翻转行或列 row为ture表示翻转行,反之表示翻转列
public void reverse(int[][] A, int num, boolean row) {
    if (row) {
        for (int i = 0; i < A[0].length; i++) {
            A[num][i] = 1 - A[num][i];
        }
    } else {
        for (int i = 0; i < A.length; i++) {
            A[i][num] = 1 - A[i][num];
        }
    }
}

优化版本:思路是完全一致的,实现的方式要简洁很多

  1. 没有必要真正的进行翻转,只需要按照贪心的思想统计即可
  2. 计算结果使用位运算 累加每一列的结果,每一列 1 的数量用贪心的思想求出
public int matrixScore1(int[][] A) {
    int m = A.length, n = A[0].length;
    // 计算第一列的结果
    int ret = m * (1 << (n - 1));

    // 累加余下每一列的结果
    for (int j = 1; j < n; j++) {
        // 该列 1 的数量,没有翻转累加 A[i][j],翻转过累加 (1 - A[i][j])
        int nOnes = 0;
        for (int i = 0; i < m; i++) {
            if (A[i][0] == 1) {
                nOnes += A[i][j];
            } else {
                nOnes += (1 - A[i][j]);
            }
        }
        // 计算 1 和 0 的较大者,即为该列翻转后 1 的数量
        int k = Math.max(nOnes, m - nOnes);
        ret += k * (1 << (n - 1 - j));
    }
    return ret;
}

执行结果

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值