携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第28天,点击查看活动详情
一个 n x n 的二维网络 board 仅由 0 和 1 组成 。每次移动,你能任意交换两列或是两行的位置。
返回 将这个矩阵变为 “棋盘” 所需的最小移动次数 。如果不存在可行的变换,输出 -1。
“棋盘” 是指任意一格的上下左右四个方向的值均与本身不同的矩阵。
示例 1:
输入: board = [[0,1,1,0],[0,1,1,0],[1,0,0,1],[1,0,0,1]]
输出: 2
解释: 一种可行的变换方式如下,从左到右:
第一次移动交换了第一列和第二列。
第二次移动交换了第二行和第三行。
示例 2:
输入: board = [[0, 1], [1, 0]]
输出: 0
解释: 注意左上角的格值为0时也是合法的棋盘,也是合法的棋盘.
示例 3:
输入: board = [[1, 0], [1, 0]]
输出: -1
解释: 任意的变换都不能使这个输入变为合法的棋盘。
提示:
n == board.lengthn == board[i].length2 <= n <= 30board[i][j]将只包含0或1
解题
/**
* @param {number[][]} board
* @return {number}
*/
var movesToChessboard = function (board) {
const h = new Map();
const v = new Map();
const len = board.length;
const num = Math.pow(2, len) - 1;
const setMap = (v, map, i) => {
let item = map.get(v);
if (item) {
item.push(i);
} else if (map.size >= 2) {
return false;
} else {
map.set(v, [i]);
}
return true;
};
const valid = (arr) => {
if (arr.length != 2 || (arr[0][0] ^ arr[1][0]) != num) return false;
const diff = Math.abs(arr[0][1].length - arr[1][1].length);
if (diff > 1) return false;
return true;
};
const getCount = (arr) => {
let oddCount = 0;
let midCount = ((len + 1) >> 1) | 0;
for (let i = 0; i < arr[0][1].length; i++) {
if (arr[0][1][i] & 1) {
oddCount++;
}
}
if (len & 1) {
if (midCount === arr[0][1].length) {
return oddCount;
} else {
return midCount - 1 - oddCount;
}
} else {
return Math.min(oddCount, midCount - oddCount);
}
};
for (let i = 0; i < len; i++) {
let hValue = 0;
let vValue = 0;
for (let j = 0; j < len; j++) {
hValue = (hValue << 1) + board[i][j];
vValue = (vValue << 1) + board[j][i];
}
if (!setMap(hValue, h, i) || !setMap(vValue, v, i)) return -1;
}
const hArr = Array.from(h);
const vArr = Array.from(v);
if (!valid(hArr) || !valid(vArr)) return -1;
return getCount(hArr) + getCount(vArr);
};