1. 程式人生 > 其它 >【LeetCode】每日一題861. 翻轉矩陣後的得分

【LeetCode】每日一題861. 翻轉矩陣後的得分

技術標籤:每日一題javaleetcode貪心演算法

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;
}

執行結果

在這裡插入圖片描述