1. 程式人生 > >LeetCode | Set Matrix Zeroes(矩陣相應行列清零)

LeetCode | Set Matrix Zeroes(矩陣相應行列清零)

Given a m x n matrix, if an element is 0, set its entire row and column to 0. Do it in place.

Follow up:

Did you use extra space?
A straight forward solution using O(mn) space is probably a bad idea.
A simple improvement uses O(m + n) space, but still not the best solution.
Could you devise a constant space solution?


題目解析:

碰到一個無法下手的問題,可以從最複雜的開始,一點一點去優化。既然要求不能使用額外空間,那麼利用額外空間就很容易做了,現在思考怎麼去應該額外空間,然後推出如何不適用額外空間來解題。

方案一:

建立一個一模一樣的二維陣列O(mn),其中也填充相同的資料。當在原陣列中碰到0,就在備份陣列中的i行j列相應的清除為0即可!這是最簡單最直觀的方案。

方案二:

如何進行優化?就跟n皇后問題一樣,只需要用一行陣列中某一個元素記錄哪一行需要清零,用一列陣列中的某一個元素記錄哪一列需要清零。然後遍歷這兩個陣列,對原陣列清零即可。這樣空間複雜度降低到O(m+n)。

方案三:

既然題目要求不適用額外空間,我們就從方案二找突破口。看能不能用某一列和某一行充當方案二的輔助空間。

----->思路一

一開始沒有想到充當輔助空間,只是想當(i,j)為0的時候,將這一行其他非零元素變為0,為0的元素變成-1(要保證這個資料在整個陣列中不出現),列也同理。當掃描到下一行(i,j)的時候,就相應的判斷(i-1,j)的值,如果為0,就無所謂;如果為-1就將該值變成-1,表示這一列是要清除的。

當掃描完以後,將所有的-1變成0即可。當然掃描每一行的某個值的時候,要記錄這一行之前是否出現0元素:沒有就直接看“頭頂”元素。如果出現要結合頭頂元素來判斷。

整個過程比較複雜,不過能實現要達到的目標。

----->思路二

先找到第一個為0的位置(i,j),那麼i行j列肯定要清零。這一行和這一列來當標記陣列。當其他位置(k1,k2)為0時,就讓(i,k2)和(k1,j)為0。掃描完以後,在根據這兩個標記陣列來進行相應的清空。

程式碼如下:

class Solution {
public:
    void setZeroes(vector<vector<int> > &matrix) {
        int m = matrix.size();
        if(m < 1) return ;
        int n = matrix.front().size();
        
        //found first zero
        int row = -1 ,  col = -1;;
        for(int i = 0 ; i < m ; i ++) {
            for(int j = 0 ; j < n ; j++) {
                if(matrix[i][j] == 0) {
                    row = i;
                    col = j;
                    break;
                }
            }
            if(row != -1) break;
        }
        
        if(row == -1) return;
        //col
       // for(int i = 0 ; i < n ; i++) matrix[row][i] = 0;
        //row
    //    for(int i = 0 ; i < m ; i++) matrix[i][col] = 0;
        
        //row , col to record if has zero
        for(int i = 0 ; i < m ; i++) {
            for(int j = 0 ; j < n ; j++) {
                if(matrix[i][j] == 0) {
                    matrix[row][j] = 0;
                    matrix[i][col] = 0;
                }
            }
        }
        //fill col
        for(int i = 0 ; i < n ; i++) {
            if(i != col && matrix[row][i] == 0) {
                //fill
                for(int j = 0 ; j < m ; j++) {
                    matrix[j][i] = 0;
                }
            }
        }
        //fill row
        for(int i = 0 ; i < m ; i++) {
            if(i != row && matrix[i][col] == 0) {
                //fill
                for(int j = 0 ; j < n ; j++) {
                    matrix[i][j] = 0;
                }
            }
        }
        //col
        for(int i = 0 ; i < n ; i++) matrix[row][i] = 0;
        //row
        for(int i = 0 ; i < m ; i++) matrix[i][col] = 0;
    }
};


---->思路三:

既然我們要對某一行和某一列清零(i行j列),則相應的(i,0)和(0,j)肯定也要清零的。那麼可以讓0行和0列充當標記陣列。

需要注意:

1:標記陣列原始資料中是否已經存在0元素,要先做標記,然後忽略這兩個陣列存在的價值,專門去標記,最後再對兩個陣列操作。

2:第一遍的時候,只掃描,對標記陣列進行清零,其他元素不操作。最後再統一清零。

程式碼如下:

class Solution {
public:
    void setZeroes(vector<vector<int> > &matrix) {
        const int ROW = matrix.size();
        if (ROW == 0)
            return;
        const int COL = matrix[0].size();
        if (COL == 0)
            return;
        
        // we store the 0 information in
        // the 1st row and 1st col
        bool R00 = false;
        for(int i = 0; i < COL; ++i)
            if (matrix[0][i] == 0)
            {
                R00 = true;
                break;
            }
        bool C00 = false;
        for(int i = 0; i < ROW; ++i)
            if (matrix[i][0] == 0)
            {
                C00 = true;
                break;
            }
        
        // now traverse the remaining parts of
        // the matrix and store 0 into the 
        // first row
        for(int i = 1; i < ROW; ++i)
            for(int j = 1; j < COL; ++j)
                if (matrix[i][j] == 0)
                {
                    matrix[i][0] = 0;
                    matrix[0][j] = 0;
                }
                
        // use the first row/col information to
        // fill zeros
        for(int i = 1; i < ROW; ++i)
            if (matrix[i][0] == 0)
                for(int j = 1; j < COL; ++j)
                    matrix[i][j] = 0;
        
        for(int i = 1; i < COL; ++i)
            if (matrix[0][i] == 0)
                for(int j = 1; j < ROW; ++j)
                    matrix[j][i] = 0;
        
        // Finally check the 1st row/col
        if (R00)
            fill(begin(matrix[0]), end(matrix[0]), 0);
        if (C00)
            for(int i = 0; i < ROW; ++i)
                matrix[i][0] = 0;
        
        return;
    }
};