準備開一個力扣解題的系列,督促本身天天刷題,就從今天開始。
java
給定一個 m x n 的矩陣,若是一個元素爲 0,則將其所在行和列的全部元素都設爲 0。請使用原地算法。git
示例 1:github
輸入: [ [1,1,1], [1,0,1], [1,1,1] ] 輸出: [ [1,0,1], [0,0,0], [1,0,1] ]
示例 2:算法
輸入: [ [0,1,2,0], [3,4,5,2], [1,3,1,5] ] 輸出: [ [0,0,0,0], [0,4,5,0], [0,3,1,0] ]
進階:優化
原題url:https://leetcode-cn.com/problems/set-matrix-zeroes/url
其實題目自己不難,只要判斷出哪些數字是0,將其所在行和列記錄一下, 最終所有置0便可,關鍵在於你所須要消耗的空間是多少。code
首先我想到的是用一個數字進行表示,用二進制表示,一共m + n
位,其中前m
位表示行,後n
位表示列,矩陣中哪一個數字爲0,則其行列所在位的數字爲1,也就是加上相應的二進制數。爲了避免重複添加,能夠用&
進行判斷。來看看代碼是什麼:對象
class Solution { public void setZeroes(int[][] matrix) { // 轉化爲二進制後,前m位表示列,後n位表示行 int temp = 0; for (int i = 0; i < matrix.length; i++) { for (int j = 0; j < matrix[i].length; j++) { if (matrix[i][j] != 0) { continue; } // 第j列是否已經被設置爲0 int num = 1 << (matrix.length + j); if ((temp & num) != num) { // 若是沒有,則加上 temp += num; } // 第i行是否已經被設置爲0 num = 1 << i; if ((temp & num) != num) { // 若是沒有,則加上 temp += num; } } } for (int i = 0; i < matrix.length; i++) { for (int j = 0; j < matrix[i].length; j++) { // 第j列是否已經被設置爲0 int numCol = 1 << (matrix.length + j); // 第i行是否已經被設置爲0 int numRow = 1 << i; if ((temp & numRow) == numRow || (temp & numCol) == numCol) { // 若是有,則設置當前值爲0 matrix[i][j] = 0; } } } } }
理論上沒什麼問題,提交以後報錯。當m
和n
很大時,數字會很大,這個時候temp
會越界。我想着是否是求2的冪用Math.pow()
,而且 temp 的類型改成 long ,是否是就能夠了,說幹就幹:內存
class Solution { public void setZeroes(int[][] matrix) { // 轉化爲二進制後,前m位表示列,後n位表示行 long temp = 0; for (int i = 0; i < matrix.length; i++) { for (int j = 0; j < matrix[i].length; j++) { if (matrix[i][j] != 0) { continue; } // 第j列是否已經被設置爲0 long num = (long)Math.pow(2, matrix.length + j); if ((temp & num) != num) { // 若是沒有,則加上 temp += num; } // 第i行是否已經被設置爲0 num = (long)Math.pow(2, i); if ((temp & num) != num) { // 若是沒有,則加上 temp += num; } } } for (int i = 0; i < matrix.length; i++) { for (int j = 0; j < matrix[i].length; j++) { // 第j列是否已經被設置爲0 long numCol = (long)Math.pow(2, matrix.length + j); // 第i行是否已經被設置爲0 long numRow = (long)Math.pow(2, i); if ((temp & numRow) == numRow || (temp & numCol) == numCol) { // 若是有,則設置當前值爲0 matrix[i][j] = 0; } } } } }
好吧,依然不能夠,看來確實很大,最終仍是溢出變成負數了。看來得另尋他法了。leetcode
若是1個數字不夠,那麼多來幾個數字應該也是不夠用的,並且若是用的太多也可能會增加到m + n
,空間依舊比較多。這個時候我也想不出來,看了看別人的解法,讓我頓時領悟——利用矩陣自己。
就是利用矩陣的第一行和第一列來記錄須要置零的行和列,至於第一行和第一列是否須要置零,則能夠單獨拿兩個 boolean 對象來表示。(怎麼好的思路,爲啥我就是沒想到呢)來看看代碼:
class Solution { public void setZeroes(int[][] matrix) { // 用第一行和第一列表示當前行和當前列是否須要置0 // 單獨計算第一行和第一列是否須要置0 int row = matrix.length; int col = matrix[0].length; // 第一行是否須要置0 boolean row0 = false; for (int i = 0; i < col; i++) { if (matrix[0][i] == 0) { row0 = true; break; } } // 第一列是否須要置0 boolean col0 = false; for (int i = 0; i < row; i++) { if (matrix[i][0] == 0) { col0 = true; break; } } // 判斷每一行每一列是否須要置0 for (int i = 1; i < row; i++) { for (int j = 1; j < col; j++) { if (matrix[i][j] != 0) { continue; } matrix[i][0] = matrix[0][j] = 0; } } // 置0 for (int i = 1; i < row; i++) { for (int j = 1; j < col; j++) { if (matrix[i][0] == 0 || matrix[0][j] == 0) { matrix[i][j] = 0; } } } // 第一行是否須要都置0 if (row0) { for (int i = 0; i < col; i++) { matrix[0][i] = 0; } } // 第一列是否須要都置0 if (col0) { for (int i = 0; i < row; i++) { matrix[i][0] = 0; } } } }
終於經過了,執行用時:2ms
,內存消耗:43.5MB
。那麼是否能夠繼續優化呢?
首先,須要第一行和第一列都判斷一遍的嗎?能夠只判斷其中一個便可,好比只判斷第一列是否須要置零,那麼第一行是否須要置零就能夠依賴matrix[0][0]
了。在置零的時候,也是將第一列單獨判斷便可。
須要注意的是,置零操做須要從後往前,由於matrix[0][0]
會有雙重含義,因此最後判斷便可。來看看代碼:
class Solution { public void setZeroes(int[][] matrix) { // 第一列是否須要置零 boolean col0 = false; int row = matrix.length; int col = matrix[0].length; // 判斷是否須要置零 for (int i = 0; i < row; i++) { // 若是第一列不須要置零,而且第一列有數字是0,則col0設置爲true if (!col0 && matrix[i][0] == 0) { col0 = true; } for (int j = 1; j < col; j++) { if (matrix[i][j] == 0) { matrix[i][0] = matrix[0][j] = 0; } } } // 置零,從後往前開始,由於若是從前日後,第一行若是由於第一列置爲0,會對以後結果誤導 for (int i = row - 1; i >= 0; i--) { // 第一列不動 for (int j = col - 1; j >= 1; j--) { if (matrix[i][0] == 0 || matrix[0][j] == 0) { matrix[i][j] = 0; } } // 第一列置零 if (col0) { matrix[i][0] = 0; } } } }
以上就是這道題目個人解答過程了,不知道你們是否理解了。我準備把我刷力扣的過程記錄下來,做爲這個系列的內容,但願能和你們多多分享。
有興趣的話能夠訪問個人博客或者關注個人公衆號、頭條號,說不定會有意外的驚喜。
公衆號:健程之道