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;
}
}
}
};