【LeetCode】每日一題861. 翻轉矩陣後的得分
阿新 • • 發佈:2020-12-15
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 的數量用貪心的思想求出
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;
}