[LeetCode] 73. Set Matrix Zeroes 矩阵置零
Given an m x n
integer matrix matrix
, if an element is 0
, set its entire row and column to 0
's.
You must do it in place.
Example 1:
Input: matrix = [[1,1,1],[1,0,1],[1,1,1]] Output: [[1,0,1],[0,0,0],[1,0,1]]
Example 2:
Input: matrix = [[0,1,2,0],[3,4,5,2],[1,3,1,5]] Output: [[0,0,0,0],[0,4,5,0],[0,3,1,0]]
Constraints:
m == matrix.length
n == matrix[0].length
1 <= m, n <= 200
-2^31 <= matrix[i][j] <= 2^31 - 1
Follow up:
- A straightforward 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?
据说这题是 CareerCup 上的原题,也不算难,虽然博主也是看了网上的解法照着写的,但是下次遇到绝对想的起来。这道题中说的空间复杂度为 O(mn) 的解法自不用多说,直接新建一个和 matrix 等大小的矩阵,然后一行一行的扫,只要有0,就将新建的矩阵的对应行全赋0,行扫完再扫列,然后把更新完的矩阵赋给 matrix 即可,这个算法的空间复杂度太高。将其优化到 O(m+n) 的方法是,用一个长度为m的一维数组记录各行中是否有0,用一个长度为n的一维数组记录各列中是否有0,最后直接更新 matrix 数组即可。这道题的要求是用 O(1) 的空间,那么就不能新建数组,就用原数组的第一行第一列来记录各行各列是否有0.
- 先扫描第一行第一列,如果有0,则将各自的 flag 设置为 true
- 然后扫描除去第一行第一列的整个数组,如果有0,则将对应的第一行和第一列的数字赋0
- 再次遍历除去第一行第一列的整个数组,如果对应的第一行和第一列的数字有一个为0,则将当前值赋0
- 最后根据第一行第一列的 flag 来更新第一行第一列
解法一:
class Solution { public: void setZeroes(vector<vector<int>>& matrix) { int m = matrix.size(), n = matrix[0].size(); bool rowZero = false, colZero = false; for (int i = 0; i < m; ++i) { if (matrix[i][0] == 0) colZero = true; } for (int i = 0; i < n; ++i) { if (matrix[0][i] == 0) rowZero = true; } for (int i = 1; i < m; ++i) { for (int j = 1; j < n; ++j) { if (matrix[i][j] == 0) { matrix[0][j] = 0; matrix[i][0] = 0; } } } for (int i = 1; i < m; ++i) { for (int j = 1; j < n; ++j) { if (matrix[0][j] == 0 || matrix[i][0] == 0) { matrix[i][j] = 0; } } } if (rowZero) { for (int i = 0; i < n; ++i) matrix[0][i] = 0; } if (colZero) { for (int i = 0; i < m; ++i) matrix[i][0] = 0; } } };
我们可以稍微优化一下上面的解法,少用几个 for 循环,这里只用一个变量 colZero 来表示首列是否有0存在即可,首行不用单独去记录,因为其是否为0会在 matrix[0][0] 中记录。这里只需要两个嵌套 for 循环就可以了,第一个嵌套 for 循环的i是从0开始遍历的,若首列有0,则将 colZero 标记为 true。内层 for 循环的j是从1开始遍历的,若 matrix[i][j] 为0了,则将 matrix[0][j] 和 matrix[i][0] 都赋值为0。然后开始第二个嵌套 for 循环,外层的 for 循环的i是从 m-1 往前遍历到0,内层的 for 循环的j是从 n-1 往前遍历到1,若 matrix[0][j] 和 matrix[i][0] 中任意一个为0了,则将 matrix[i][j] 赋值为0,同时在外层 for 循环的遍历过程中,判断若 colZero 为 true,则将 matrix[i][0] 赋值为0,这就保证了首列被更新了,参见代码如下:
解法二:
class Solution { public: void setZeroes(vector<vector<int>>& matrix) { int m = matrix.size(), n = matrix[0].size(); bool colZero = false; for (int i = 0; i < m; ++i) { if (matrix[i][0] == 0) colZero = true; for (int j = 1; j < n; ++j) { if (matrix[i][j] == 0) { matrix[0][j] = 0; matrix[i][0] = 0; } } } for (int i = m - 1; i >= 0; --i) { for (int j = n - 1; j >= 1; --j) { if (matrix[0][j] == 0 || matrix[i][0] == 0) { matrix[i][j] = 0; } } if (colZero) matrix[i][0] = 0; } } };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/73
类似题目:
Number of Laser Beams in a Bank
Minimum Operations to Remove Adjacent Ones in Matrix
Remove All Ones With Row and Column Flips II
参考资料:
https://leetcode.com/problems/set-matrix-zeroes/
https://leetcode.com/problems/set-matrix-zeroes/solutions/26014/any-shorter-o-1-space-solution/