We have a two dimensional matrix `A` where each value is `0` or `1`.
A move consists of choosing any row or column, and toggling each value in that row or column: changing all 0
s to 1
s, and all 1
s to 0
s.
After making any number of moves, every row of this matrix is interpreted as a binary number, and the score of the matrix is the sum of these numbers.
Return the highest possible score.
Example 1:
Input: [[0,0,1,1],[1,0,1,0],[1,1,0,0]]
Output: 39
Explanation: Toggled to [[1,1,1,1],[1,0,0,1],[1,1,1,1]].
0b1111 + 0b1001 + 0b1111 = 15 + 9 + 15 = 39
Note:
1 <= A.length <= 20
1 <= A[0].length <= 20
A[i][j]
is0
or1
.
這道題給了我們一個只有0和1的二維數組,說是每一行代表一個數字,我們可以任意地翻轉任意行和列,問如何能使得每一行代表的數字之和最大。在博主看來,這道題還是挺有意思的,因為你可以寫的很復雜,但如果思路巧妙的話,也可以寫的很簡潔。當然最暴力的解法就是遍歷所有的組合,對於一個 mxn 大小的矩陣,每一行都可以選擇翻與不翻,同理,每一列也可以選擇翻與不翻,那么總共就有 2^(m+n) 種情況,寫起來比較復雜。
這道題最巧妙的解法是用貪婪算法 Greedy Algorithm 來解的,由於數字是由二進制表示的,那么最高位的權重是要大於其他位總和的,比如 1000 就要大於 0111 的,所以當最高位是0的時候,無論如何都是需要翻轉當前行的,那么對於 mxn 的數組來說,每行的二進制數共有n位,最高位是1的話,就是 1<<(n-1),那么共有m行,所以至少能將 m*(1<<(n-1)) 這么大的值收入囊中,既然最高值一定要是1,那么每一行的翻轉情況就確定了,若還想增大數字之和,就只能看各列是否還能翻轉了,而且是從次高位列開始看,因為最高位列必須保證都是1。由於每一行的翻轉情況已經確定了,那么如何才能確定其他位到底是0還是1呢,這里就有個 trick,此時就要看它跟最高位是否相同了,若相同的話,不管最高位初始時是0還是1,最終都要變成1,那么當前位一定最終也會變成1,而一旦跟最高位相反,那么最后一定會是0。我們翻轉當前列的條件肯定是希望翻轉之后1的個數要更多一些,這樣值才能增加,所以就要統計每列當前的1的個數,若小於0的個數,才進行翻轉,然后乘以該列的值,對於第j列,其值為 1<<(n-1-j),參見代碼如下:
class Solution {
public:
int matrixScore(vector<vector<int>>& A) {
int m = A.size(), n = A[0].size(), res = (1 << (n - 1)) * m;
for (int j = 1; j < n; ++j) {
int cnt = 0;
for (int i = 0; i < m; ++i) {
cnt += (A[i][j] == A[i][0]);
}
res += max(cnt, m - cnt) * (1 << (n - 1 - j));
}
return res;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/861
參考資料:
https://leetcode.com/problems/score-after-flipping-matrix/
[LeetCode All in One 題目講解匯總(持續更新中...)](https://www.cnblogs.com/grandyang/p/4606334.html)