1. 程式人生 > 實用技巧 >LeetCode73. 矩陣置零

LeetCode73. 矩陣置零

解法一(使用O(mn)空間)

可以開一個額外的二維陣列,記錄每個位置的元素是否已被訪問過。

然後我們遍歷原來的二維陣列,只要沒被訪問過且元素為0,那麼就將該元素所在的行和列的元素值置為0,
並且將這一行的所有元素都設定為已經訪問過,以免之後的遍歷碰到被置為0的元素也將那一行那一列的元素置為0.

這裡要注意,對於一個為0且未被訪問的元素所在的行和列的元素置0的時候,要跳過本來就為0的元素,因為可能之後的遍歷
到了其他的本來就為0的元素,由於置了那個元素的狀態為訪問過,就會跳過這個元素,導致沒有將那個元素所在的行和列所在的
元素置0.

程式碼如下:

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        int rows = matrix.size(), cols = matrix[0].size();      
        vector<vector<bool>> visited(rows, vector<bool>(cols));      //記錄每個元素是否已被訪問過
        for(int i = 0; i < rows; ++i) {
            for(int j = 0; j < cols; ++j) {
                if(visited[i][j] == false && matrix[i][j] == 0) {      //只有當元素為0且未被訪問過時,才修改這一行這一列的元素
                    for(int k = 0; k < rows; ++k) {
                        if(matrix[k][j] != 0) {                  //這個if判斷不能少,目的是為了防止將這一列本來就為0的元素置為已經訪問過,導致無法將那個本就為0的元素所在的行和列的元素置0, 下面的if語句同理
                            matrix[k][j] = 0;
                            visited[k][j] = true;
                        }
                    }
                    for(int k = 0; k < cols; ++k) {
                        if(matrix[i][k] != 0) {
                            matrix[i][k] = 0;
                            visited[i][k] = true;
                        }
                    }
                }
            }
        }
    }
};

解法二(使用O(m + n)空間)

給每一個元素都設定一個訪問狀態需要開二維陣列,有點麻煩。

由於我們只需要把0所在的行和列的元素置為0,所以我們可以這樣:遍歷一遍陣列,如果某個元素為0,
那麼我們記錄一下這個元素的行號和列號。

最後把所有我們記錄過的行和列的元素全部置為0即可。

使用這種方法需要開一個O(n)的陣列記錄每一行是否有0元素,還要開一個O(m)陣列記錄每一列是否有0元素。
因此空間開銷是O(m + n)。

程式碼如下:

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        int rows = matrix.size(), cols = matrix[0].size();
        vector<int> rowHasZero(rows), colHasZero(cols);      //兩個陣列分別記錄每一行和每一列是否有0元素
        for(int i = 0; i < rows; ++i) {
            for(int j = 0; j < cols; ++j) {
                if(matrix[i][j] == 0) {                  //如果某個元素為0,記錄下它的行號和列號
                    rowHasZero[i] = 1;
                    colHasZero[j] = 1;
                }
            }
        }
        for(int i = 0; i < rows; ++i) {      
            if(rowHasZero[i] == 1) {                     //將存在0元素的行的所有元素都置0
                for(int j = 0; j < cols; ++j) {
                    matrix[i][j] = 0;
                }
            }
        }
        for(int j = 0; j < cols; ++j) {                  //將存在0元素的列的所有元素都置0
            if(colHasZero[j] == 1) {
                for(int i = 0; i < rows; ++i) {
                    matrix[i][j] = 0;
                }
            }
        }
    }
};

解法三 (使用常數空間)

由於要將0元素所在的行和列所在的所有元素都置為0,我們就需要記錄哪些行哪些列含有0元素,但是又不能開陣列記錄,那怎麼辦呢?

可以考慮直接用原陣列記錄,比如解法二里開了一個列大小的陣列記錄每一行是否有0,又開了一個行大小的陣列記錄每一列是否有0.

我們可以直接在第0行和第0列記錄! 比如,如果martix[i][j]為0,那麼我們就讓martix[i][0]為0,表示第i行含有元素0,之後需要將該行所有元素都改為0.
再讓martix[0][j]為0,表示第j列含有元素0,之後需要講該列所有元素都改為0.

這樣我們就不需要額外開陣列了,但是又有個問題,這樣修改了原來的第0行和第0列的元素,咋辦?

問題不大,只能開常數空間,不代表不能開空間,我們額外用兩個變數記錄第0行和第0列是否有0,如果有,在最後就將第0行(列)的所有元素改為0,
如果沒有,那麼如果第0行或第0列的元素所在的行(列)沒有0,那麼他們還是原來的值(沒有被修改),如果有,那說明(對第0行/列元素的修改)正好改對了呀,
反正他們最後本來就是0! 這樣就解決了空間的問題,使用常數空間就可以將矩陣置0.

程式碼如下:

class Solution {
public:
    void setZeroes(vector<vector<int>>& matrix) {
        int rows = matrix.size(), cols = matrix[0].size();
        int firstRowHasZero = 0, firstColHasZero = 0;      //判斷第0行和第0列是否有元素0
        for(int i = 0; i < cols; ++i) {
            if(matrix[0][i] == 0) {                        //如果第0行有元素0,修改firstRowHasZero,在程式最後將第0行所有元素都改為0
                firstRowHasZero = 1;
                break;
            }
        }
        for(int i = 0; i < rows; ++i) {
            if(matrix[i][0] == 0) {                        //如果第0列有元素0,修改firstColHasZero,在程式最後將第0列所有元素都改為0
                firstColHasZero = 1;
                break;
            }
        }
        for(int i = 1; i < rows; ++i) {               
            for(int j = 0; j < cols; ++j) {
                if(matrix[i][j] == 0) {
                    matrix[i][0] = 0;                 //如果某元素為0,修改martix[i][0]為0,表示第i行的元素最後需要全部改為0
                    break;
                }
            }
        }
        for(int j = 1; j < cols; ++j) {
            for(int i = 0; i < rows; ++i) {
                if(matrix[i][j] == 0) {
                    matrix[0][j] = 0;                 //如果某元素為0,修改martix[i][0]為0,表示第j列的元素最後需要全部改為0
                    break;
                }
            }
        }
        for(int i = 1; i < rows; ++i) {
            if(matrix[i][0] == 0) {                  //第i行有0元素,把第i行所有元素都改為0
                for(int j = 1; j < cols; ++j) {
                    matrix[i][j] = 0;
                }
            }
        }
        for(int j = 1; j < cols; ++j) {
            if(matrix[0][j] == 0) {                  //第j列有0元素,把第j列所有元素都改為0
                for(int i = 1; i < rows; ++i) {
                    matrix[i][j] = 0;
                }
            }
        }
        if(firstRowHasZero) {
            for(int j = 0; j < cols; ++j) {          //第0行有0元素,把第0行所有元素都改為0
                matrix[0][j] = 0;
            }
        }
        if(firstColHasZero) {
            for(int i = 0; i < rows; ++i) {          //第0列有0元素,把第0列所有元素都改為0
                matrix[i][0] = 0;
            }
        }
    }
};