https://leetcode.com/problems/transform-to-chessboard/
没思路,看了答案。这道题没有套路,需要发现独特的规律,参考:
简单易懂的解法
【Python3】要么等于第一行 要么和第一行完全相反
代码是看着答案的思路,一句一句翻译过来的…详细原理见注释。
class Solution {
public int movesToChessboard(int[][] board) {
// 规则#1
// 所有的"行",要么等于第0行,要么和第0行完全相反
// 列也一样,但不需要去检查列,因为如果"行"合法,列必然合法,因此只需要判断"行"就行
int N = board.length;
boolean[] reverse = new boolean[N];
for (int i = 1; i < N; i++) {
reverse[i] = board[i][0] != board[0][0];
}
for (int i = 1; i < N; i++) {
for (int j = 0; j < N; j++) {
if (reverse[i] && board[i][j] == board[0][j]) return -1;
}
}
// 规则#2
// 每行的"1"的个数必须要么等于"0"的个数,要么相差1。因为规则#1已经通过,这次只要检查第0"行"就行。
// 这次除了第0行,还需要检查第0列。
int one = 0;
for (int i = 0; i < N; i++) {
if (board[0][i] == 1) one++;
}
if (Math.abs(N - 2 * one) > 1) return -1;
one = 0;
for (int i = 0; i < N; i++) {
if (board[i][0] == 1) one++;
}
if (Math.abs(N - 2 * one) > 1) return -1;
// 【计算交换次数】
// 只需要计算第0行和第0列的交换次数就行,因为满足规则#1,所以剩下的行列肯定自动合法
// 【首先,变换行】
// (1)假设左上角单元格是0,则可推知整行的每个单元格。计算实际与目标的diff个数,如果diff为偶数,则变化次数为差异点个数的一半
// (因为交换一次可以消除两个差异点)。如果diff为奇数,则无法变换为目标风格
// (2)假设左上角单元格是1。同上。
// (3)最后,选交换次数最小的作为行交换次数。
// 【然后,变换列】
// 列的变换算法和行没有任何差异,且行交换结果不影响列交换结果。
// 【最后,行列交换次数相加】
// 就是最终结果。
int diffRow = 0;
int swapRow;
for (int i = 0; i < N; i++) { // 假设左上角为0,计算"行"交换个数
if (i % 2 == 0) diffRow += board[0][i];
else diffRow += (1 - board[0][i]);
}
if (diffRow % 2 == 0) {
swapRow = diffRow / 2;
if ((N - diffRow) % 2 == 0) swapRow = Math.min(swapRow, (N - diffRow) / 2); // N-diff是假设左上角为1的情况
} else {
swapRow = (N - diffRow) / 2;
}
// 行交换结果不影响列交换结果
int diffCol = 0;
int swapCol;
for (int i = 0; i < N; i++) { // 假设左上角为0,计算"列"交换个数
if (i % 2 == 0) diffCol += board[i][0];
else diffCol += (1 - board[i][0]);
}
if (diffCol % 2 == 0) {
swapCol = diffCol / 2;
if ((N - diffCol) % 2 == 0) swapCol = Math.min(swapCol, (N - diffCol) / 2); // N-diff是假设左上角为1的情况
} else {
swapCol = (N - diffCol) / 2;
}
return swapRow + swapCol;
}
}



