LeetCode 1284. Minimum Number of Flips to Convert Binary Matrix to Zero Matrix (最少翻轉次數將二進制矩陣全部置爲0)

給一個矩陣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.
 
也就是。。。。最多也就9個格子。。。。。暴力怎麼都能搞出來的。。。。。
 
首先分析每個格子要麼不反轉,要麼翻轉一次,因爲翻轉2次的效果和不反轉是一樣的,不需要在考慮兩次及以上的情況。
 
所以問題很簡單,DFS 瞎搞搞就好了~~~
 
/**
 * @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);
};
View Code

 

當然,既然題目是二進制矩陣,所以可以有更優雅點的做法,就是用一個二進制數來表示一種情況,二進制數的每一個表示對應格子是否翻轉。那麼,如果有n個格子,0~(2^n-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);
    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;
};
View Code

 

稍微不那麼暴力的做法,首先枚舉第一行的反轉方式,如果第一行某個格子反轉後爲1,那麼對應位置第2行必翻轉,以此類推。。。代碼有時間加。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章