算法練習每日一題:翻轉矩陣後的得分

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

來源:力扣(LeetCode)
鏈接:https://leetcode-cn.com/problems/score-after-flipping-matrix

class Solution:
    def matrixScore(self, A):
        rst = 0
        R, C = len(A),len(A[0])
        for c in range(0, C):
            col = 0
            for r in range(0, R):
                col += A[r][c] ^ A[r][0]
            rst += max(col, R-col)*(2**(C-1-c))
        return rst
A = [[0,0,1,1],[1,0,1,0],[1,1,0,0]]
print(Solution().matrixScore(A))
39

題解

  • 分析

注意到將一行或者一列翻轉兩次及以上是沒有意義的,因爲翻轉兩次等價於沒有進行任何翻轉。因此每一行和每一列最多被翻轉了一次。
我們首先枚舉每一行是否被翻轉,對於一個 R 行 C 列的矩陣,可能的翻轉情況有 2^R 種。隨後對於每一列,1 的個數應該越多越好。如果某一列當前有 k 個 1,那麼翻轉後將會有 R - k 個 1,我們比較 k 和 R - k 的大小,就可以判斷這一列是否需要翻轉。

對於任意一行而言,如果這一行的第一個數 1,那麼它的分數一定會比不是 1 要高。這是因爲第一個 1 代表了 2C−12^{C-1}2C−1,而如果第一位是 0,那麼即使後面所有的位置都是 1,這一行的值最多也是 2C−2+⋯+21+20=2C−1−12^{C-2} + \cdots + 2^1 + 2^0 = 2^{C-1}-12C−2+⋯+21+20=2C−1−1,小於 2C−12^{C-1}2C−1。因此我們不需要枚舉每一行是否需要翻轉,而是變爲:如果該行的第一位是 0,則翻轉,否則不翻轉。

  • 算法

設矩陣有 R 行 C 列,我們用一個 R 位的二進制數 state 表示每一行是否被翻轉,state 的範圍是 [0 … 2^R)。

如果該行的第一位是 0 則翻轉,否則不翻轉(這可以通過代碼 A[r][c] ^= A[r][0] 直接實現),並在行翻轉完畢後,對第一列進行翻轉,這樣也使得每一行的第一位都是 1。然後我們枚舉每一列是否翻轉.
要理解位移運算!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章