這道題我沒有想到什么好的辦法,直接暴力AC了,直接遍歷兩次矩陣,第一次遍歷用兩個向量分別記錄出現0的行數和列數,第二次遍歷就判斷當前的元素的行數或者列數是否出現在之前的兩個向量中,若出現了就直接置零,否則就跳過。后面看了下空間復雜度為O(1)的解法,感覺這個思路不錯,記錄一下。
我們可以將第0行和第0列作為記錄的標志位,例如matrix[5][6] == 0
,我們就將matrix[0][6]
和matrix[5][0]
置為0,經過一次遍歷后,除了第0行和第0列的情況沒有統計出來,其余的行和列都已經遍歷結束并且打上標簽,由于打標簽會向第0行和第0列添加0,打完標簽后無法判斷其本身原本就包含0,因此在遍歷矩陣打標簽之前,我們需要遍歷矩陣的第0行和第0列,如果他們本身就有0,我們就分別用兩個變量記錄下來,至此,我們先分別遍歷了矩陣的第0行和第0列,再遍歷了矩陣的其余行和列,這就遍歷了一次矩陣,我們再遍歷一次矩陣,從下標為1的行和列開始,對于matrix[i][j],如果matrix[0][j] == 0
或matrix[i][0] == 0
,我們就直接將matrix[i][j]
置零。遍歷結束后,我們還需要對第0行和第0列進行處理,如果他們原本就包含0,則將整行或整列直接置零。這里依然是遍歷兩次數組,但是由于只進行了比較操作,而沒有進行查找操作,程序耗時要比我之前暴力AC短得多。
下面分別是暴力AC代碼(空間復雜度O(m + n))和空間復雜度O(1)的代碼。
//暴力代碼
class Solution {
public:void setZeroes(vector<vector<int>>& matrix) {vector<int> row;vector<int> column;for(int i = 0; i < matrix.size(); ++i){for(int j = 0; j < matrix[i].size(); ++j){if(matrix[i][j] == 0){row.emplace_back(i);column.emplace_back(j);}}}for(int i = 0; i < matrix.size(); ++i){for(int j = 0; j < matrix[i].size(); ++j){if(find(row.begin(), row.end(), i) == row.end() && find(column.begin(), column.end(), j) == column.end())continue;matrix[i][j] = 0;}}}
};
//空間復雜度O(1)代碼
class Solution {
public:void setZeroes(vector<vector<int>>& matrix) {bool row_flag0 = false; //判斷第0行有沒有0bool column_flag0 = false; //判斷第0列有沒有0//遍歷第0行for(int i = 0; i < matrix[0].size(); ++i){if(matrix[0][i] == 0){row_flag0 = true;break;}}//遍歷第0列for(int i = 0; i < matrix.size(); ++i){if(matrix[i][0] == 0){column_flag0 = true;break;}}//遍歷整個矩陣,在第0行和第0列標記0元素的分布情況for(int i = 1; i < matrix.size(); ++i){for(int j = 1; j < matrix[i].size(); ++j){if(matrix[i][j] == 0){matrix[i][0] = 0; //在第0列的對應位置置零matrix[0][j] = 0; //在第0行的對應位置置零}}}//開始置零for(int i = 1; i < matrix.size(); ++i){for(int j = 1; j < matrix[i].size(); ++j){if(matrix[i][0] == 0 || matrix[0][j] == 0)matrix[i][j] = 0; }}//判斷在打標記之前第0行本身有沒有0if(row_flag0){for(int i = 0; i < matrix[0].size(); ++i)matrix[0][i] = 0;}//判斷在打標記之前第0列本身有沒有0if(column_flag0){for(int i = 0; i < matrix.size(); ++i)matrix[i][0] = 0;}}
};