Weekly Contest 71 leetcode 782. Transform to Chessboard

7587 ワード

An N x N  board  contains only  0 s and  1 s. In each move, you can swap any 2 rows with each other, or any 2 columns with each other.
What is the minimum number of moves to transform the board into a "chessboard"- a board where no  0 s and no  1 s are 4-directionally adjacent? If the task is impossible, return -1.
Examples:
Input: board = [[0,1,1,0],[0,1,1,0],[1,0,0,1],[1,0,0,1]]
Output: 2
Explanation:
One potential sequence of moves is shown below, from left to right:

0110     1010     1010
0110 --> 1010 --> 0101
1001     0101     1010
1001     0101     0101

The first move swaps the first and second column.
The second move swaps the second and third row.


Input: board = [[0, 1], [1, 0]]
Output: 0
Explanation:
Also note that the board with 0 in the top left corner,
01
10

is also a valid chessboard.

Input: board = [[1, 0], [1, 0]]
Output: -1
Explanation:
No matter what sequence of moves you make, you cannot end with a valid chessboard.

Note:
  • board  will have the same number of rows and columns, a number in the range  [2, 30] .
  • board[i][j]  will be only  0 s or  1 s.

  • この問題の構想は以下の通りである:(この問題は少し難易度が高いので、私がこの時間を忙しくしてから、ゆっくり見てください)
    An observation is that, in a valid ChessBoard, any rectangle inside the board with corner  NW, NE, SW, SE  (NW here means north-west) must satisfy the validness property:  (NW xor NE) == (SW xor SE)
    Since the swap process does not break this property, for a given board to be valid, this property must hold. A corollary is that given a row,any other row must be identical to it or be its inverse(逆).For example if there is a row  01010011  in the board, any other row must be either  01010011  or  10101100 .
    With this observation, we only need to consider the first column when we're swapping rows to match the ChessBoard condition. That is,it suffies(それで十分)to find the minimum row swap to make the first column be 010101...^T or 101010...^T.(here ^T means transpose.)
    Similarly, it suffies to consider the first row when swapping columns.
    Now the problem becomes solvable, with the following steps:
  • Check if the given board satisfy the validness property defined above.
  • Find minimum row swap to make the first column valid. If not possible, return -1.
  • Find minimum column swap to make the first row valid. If not possible, return -1.
  • Return the sum of step 2 and 3.

  • この問題solutions:https://leetcode.com/problems/transform-to-chessboard/solution/
    Approach #1: Dimension Independence [Accepted]
    Intuition
    After a swap of columns, two rows that were the same stay the same, and two rows that were different stay different. Since the final state of a chessboard has only two different kinds of rows, there must have originally been only two different kinds of rows.
    Furthermore, these rows must have had half zeros and half ones, (except when the length is odd, where there could be an extra zero or one), and one row must be the opposite ( 0  changed to  1  and vice versa) of the other row. This is because moves do not change these properties either.
    Similarly, the above is true for columns.
    Now, because a row move followed by a column move is the same as a column move followed by a row move, we can assume all the row moves happen first, then all the column moves. (Note: it is not true that a row move followed by another row move is the same as those moves backwards.)
    Since there are only two kinds of rows, we want the minimum number of moves to make them alternating; and similarly for columns. This reduces to a one dimensional problem, where we have an array like  [0, 1, 1, 1, 0, 0]  and we want to know the least cost to make it  [0, 1, 0, 1, 0, 1]  or  [1, 0, 1, 0, 1, 0] .
    Algorithm
    For each set of rows (and columns respectively), make sure there are only 2 kinds of lines in the right quantities that are opposites of each other.
    Then, for each possible ideal transformation of that line, find the minimum number of swaps to convert that line to it's ideal and add it to the answer. For example,  [0, 1, 1, 1, 0, 0]  has two ideals  [0, 1, 0, 1, 0, 1]  or  [1, 0, 1, 0, 1, 0] ; but  [0, 1, 1, 1, 0]  only has one ideal  [1, 0, 1, 0, 1] .
    In Java, we use integers to represent the rows as binary numbers. We check the number of differences with  [1, 0, 1, 0, 1, 0, ...]  by xoring with  0b010101010101.....01 = 0x55555555 . To make sure we don't add extra large powers of 2, we also bitwise-AND by  0b00...0011...11  where there are  N  ones in this mask.
    class Solution {
        public int movesToChessboard(int[][] board) {
            int N = board.length;
    
            // count[code] = v, where code is an integer
            // that represents the row in binary, and v
            // is the number of occurrences of that row
            Map count = new HashMap();
            for (int[] row: board) {
                int code = 0;
                for (int x: row)
                    code = 2 * code + x;
                count.put(code, count.getOrDefault(code, 0) + 1);
            }
    
            int k1 = analyzeCount(count, N);
            if (k1 == -1) return -1;
    
            // count[code], as before except with columns
            count = new HashMap();
            for (int c = 0; c < N; ++c) {
                int code = 0;
                for (int r = 0; r < N; ++r)
                    code = 2 * code + board[r][c];
                count.put(code, count.getOrDefault(code, 0) + 1);
            }
    
            int k2 = analyzeCount(count, N);
            return k2 >= 0 ? k1 + k2 : -1;
        }
    
        public int analyzeCount(Map count, int N) {
            // Return -1 if count is invalid
            // Otherwise, return number of swaps required
            if (count.size() != 2) return -1;
    
            List keys = new ArrayList(count.keySet());
            int k1 = keys.get(0), k2 = keys.get(1);
    
            // If lines aren't in the right quantity
            if (!(count.get(k1) == N/2 && count.get(k2) == (N+1)/2) &&
                    !(count.get(k2) == N/2 && count.get(k1) == (N+1)/2))
                return -1;
            // If lines aren't opposite
            if ((k1 ^ k2) != (1< N) // ones start
                cand = Math.min(cand, Integer.bitCount(k1 ^ 0x55555555 & Nones) / 2);
    
            return cand;
        }
    }

    Complexity Analysis
    Time Complexity: O(N^2)O(N​2​​), where NN is the number of rows (and columns) in  board .
    Space Complexity: O(N)O(N), the space used by  count .