782. Transform to Chessboard
You are given an n x n binary grid board. In each move, you can swap any two rows with each other, or any two columns with each other.
Return the minimum number of moves to transform the board into a chessboard board. If the task is impossible, return -1.
A chessboard board is a board where no 0’s and no 1’s are 4-directionally adjacent.
Example 1:
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.
The first move swaps the first and second column.
The second move swaps the second and third row.
Example 2:
Input: board = [[0,1],[1,0]]
Output: 0
Explanation: Also note that the board with 0 in the top left corner, is also a valid chessboard.
Example 3:
Input: board = [[1,0],[1,0]]
Output: -1
Explanation: No matter what sequence of moves you make, you cannot end with a valid chessboard.
Constraints:
- n == board.length
- n == board[i].length
- 2 <= n <= 30
- board[i][j] is either 0 or 1.
From: LeetCode
Link: 782. Transform to Chessboard
Solution:
Ideas:
1. Convert the first row and column to bitmasks:
- Represent board[0] as rowMask, and board[:,0] as colMask.
2. Calculate their bitwise inverses:
- reverseRowMask = ~rowMask, within n bits.
- reverseColMask = ~colMask, within n bits.
3. Validate each row and column:
- Every row must match either rowMask or reverseRowMask.
- Every column must match either colMask or reverseColMask.
- If any row/column doesn’t match, return -1 (invalid board).
4. Count how many rows and columns match rowMask and colMask:
- Needed for balancing parity (how many of each type must exist).
5. Compute minimum swaps using helper getMoves():
- Count how many positions are out of place compared to ideal alternating masks (e.g. 010101… or 101010…).
- If n is even, either pattern is valid; choose the one with fewer swaps.
- If n is odd, only one alternating pattern is valid (depends on parity of 1’s).
6. Return total moves:
- If either getMoves result is -1, return -1 (impossible).
- Otherwise, return rowMoves + colMoves.
Code:
int popcount(int x) {
int count = 0;
while (x) {
count += x & 1;
x >>= 1;
}
return count;
}
int getMoves(int mask, int count, int n) {
int ones = popcount(mask);
int maskA = 0xAAAAAAAA & ((1 << n) - 1);
int mask5 = 0x55555555 & ((1 << n) - 1);
if (n % 2 == 0) {
if (ones != n / 2 || count != n / 2) return -1;
int swap0 = popcount(mask ^ maskA);
int swap1 = popcount(mask ^ mask5);
return swap0 < swap1 ? swap0 / 2 : swap1 / 2;
} else {
if (abs(n - 2 * ones) != 1 || abs(n - 2 * count) != 1) return -1;
int ideal = (ones == n / 2) ? maskA : mask5;
return popcount(mask ^ ideal) / 2;
}
}
int movesToChessboard(int** board, int boardSize, int* boardColSize){
int n = boardSize;
int rowMask = 0, colMask = 0;
for (int i = 0; i < n; ++i) {
rowMask |= (board[0][i] << i);
colMask |= (board[i][0] << i);
}
int reverseRowMask = ((1 << n) - 1) ^ rowMask;
int reverseColMask = ((1 << n) - 1) ^ colMask;
int rowCnt = 0, colCnt = 0;
for (int i = 0; i < n; ++i) {
int currRowMask = 0, currColMask = 0;
for (int j = 0; j < n; ++j) {
currRowMask |= (board[i][j] << j);
currColMask |= (board[j][i] << j);
}
if (currRowMask != rowMask && currRowMask != reverseRowMask) return -1;
if (currColMask != colMask && currColMask != reverseColMask) return -1;
if (currRowMask == rowMask) rowCnt++;
if (currColMask == colMask) colCnt++;
}
int rowMoves = getMoves(rowMask, rowCnt, n);
int colMoves = getMoves(colMask, colCnt, n);
if (rowMoves == -1 || colMoves == -1) return -1;
return rowMoves + colMoves;
}