給一個矩陣mat,每個格子都是0或1,翻轉一個格子會將該格子以及相鄰的格子(有共同邊)全部翻轉(0變爲1,1變爲0)
求問最少需要翻轉幾次將所有格子全部置爲0。
這題的重點是數據範圍,比賽結束看了眼數據範圍想把自己錘死= =
m == mat.length
n == mat[0].length
1 <= m <= 3
1 <= n <= 3
mat[i][j]
is 0 or 1.
/** * @param {number[][]} mat * @return {number} */ /** * 獲取一個二維數組的行數和列數 * @param {any[][]} matrix */ const getMatrixRowAndCol = (matrix) => matrix.length === 0 ? [0, 0] : [matrix.length, matrix[0].length]; /** * 翻轉矩陣第index個元素 * @param {any [][]} matrix * @param {number} index * @param {any} value */ function flipMatrix(matrix, x, y, r, c) { let dir = [[0,1],[0,-1],[1,0],[-1,0]]; matrix[x][y] = 1 - matrix[x][y]; for (let i = 0; i < 4; i++) { let nx = x + dir[i][0]; let ny = y + dir[i][1]; if (nx < r && nx >= 0 && ny < c && ny >= 0) { matrix[nx][ny] = 1 - matrix[nx][ny]; } } } var minFlips = function(mat) { let [r, c] = getMatrixRowAndCol(mat); const dfs = (i, j, cnt) => { // console.log(i,j,cnt); if (i === r) { if (mat.every(col => col.every(item => !item))) return cnt; return -1; } if (j === c) { return dfs(i+1, 0, cnt); } let result = -1; // not flip (i, j) if ((result = dfs(i, j+1, cnt)) != -1) { return result; } // flip (i, j) flipMatrix(mat, i, j, r, c); if ((result = dfs(i, j+1, cnt+1)) != -1) { return result; } flipMatrix(mat, i, j, r, c); return -1; } return dfs(0, 0, 0); };
/** * @param {number[][]} mat * @return {number} */ /** * 獲取一個二維數組的行數和列數 * @param {any[][]} matrix */ const getMatrixRowAndCol = (matrix) => matrix.length === 0 ? [0, 0] : [matrix.length, matrix[0].length]; /** * 翻轉矩陣第index個元素 * @param {any [][]} matrix * @param {number} index * @param {any} value */ function flipMatrix(matrix, x, y, r, c) { let dir = [[0,1],[0,-1],[1,0],[-1,0]]; matrix[x][y] = 1 - matrix[x][y]; for (let i = 0; i < 4; i++) { let nx = x + dir[i][0]; let ny = y + dir[i][1]; if (nx < r && nx >= 0 && ny < c && ny >= 0) { matrix[nx][ny] = 1 - matrix[nx][ny]; } } } var minFlips = function(mat) { let [r, c] = getMatrixRowAndCol(mat); let n = r * c; // 一共有 n 個格子 每個格子有兩種選擇 不翻轉(0) 翻轉(1) // 所以可以用 n 位二進制數來表示格子的翻轉情況 let stateNum = (1 << n) - 1; for (let state = 0; state <= stateNum; state++) { // 獲取 mat 的一個副本用來修改 let copyMat = mat.map(item => ([...item])); let flipCnt = 0; // state 代表一種翻轉情況 每一個二進制都表示對應格子是否翻轉 for (let i = 0; i < r; i++) { for (let j = 0; j < c; j++) { let index = i * c + j; if ((1 << index) & state) { flipCnt++; flipMatrix(copyMat, i, j, r, c); } } } if (copyMat.every(col => col.every(item => !item))) return flipCnt; } return -1; };
稍微不那麼暴力的做法,首先枚舉第一行的反轉方式,如果第一行某個格子反轉後爲1,那麼對應位置第2行必翻轉,以此類推。。。代碼有時間加。