Leetcode.面试题 01.08. Zero Matrix LCCI题解
Posted martinlwx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Leetcode.面试题 01.08. Zero Matrix LCCI题解相关的知识,希望对你有一定的参考价值。
-
??:为什么不能直接扫描一边的时候清零?
- ??:会搞混“修改产生的0”和“矩阵中原有的0”,遍历的后面可能会把你前面修改的0当成矩阵原有的0
-
方法一:开辟一个矩阵标记要置0的位置,空间复杂度为(O(mn))。代码略。
-
方法二:事实上我们开辟的标记矩阵中存在很大的空间浪费,我们标记的时候关心的是行坐标和列坐标
[i,j]
,由此我们可以想到开一个边表row_set
和一个列表column_set
,这样的空间复杂度就是(O(m+n))。代码略。 -
方法三
- 其实我一开始看到(O(1))的要求,脑海里的想法是
用一个特殊的int
值来表示0,不过这太不严谨了 - 问题的核心是如何区分“修改产生的0”和“矩阵中原有的0”。在方法二的基础上延申以及题目题目用常数级别的(O(1))空间的要求,我们可以想到要是能够用原来数组中的某行某列来当作
row_set
和column_set
就好了。 - 综合来考虑,我们最好的选择是第一行第一列,采用第一行第一列的原因是——因为是“十字形”(沿行沿列)置0,那么我们总会到最边缘的第一行和第一列置0。而只修改第一行第一列而不动路径上的其他位置,就不会在遍历的时候搞混“标记产生的0”和“矩阵中原有的0”
- 第二遍扫描除了第一行第一列的子矩阵,对每个位置
matrix[i][j]
检查第一行和第一列对应的标记matrix[i][0] == 0 || matrix[0][j] == 0 ?
,如果是,我们就把当前位置置0 - 采用第一行第一列的方式还会有个问题——
a[0][0]
意思是标记为第一行为0还是第一列为0,两种都可以,但只能选一个。所以我们还要再设置一个bool
变量,表示另一种情况。
- 其实我一开始看到(O(1))的要求,脑海里的想法是
-
举个例子
[
[1,3,4,7],
[3,5,0,8],
[7,8,9,5],
[5,0,4,6]
]
[
[1,0,0,7],
[0,5,0,8],
[7,8,9,5],
[0,0,4,6]
] //此时修改完了第一行和第一列的
[
[5,0,8],
[8,9,5],
[0,4,6]
] //这就是我们第二遍遍历要看的子矩阵,此时对于每个matrix[i][j],我们再检查第一行和第一列对应的位置有没有为0的即可。
//之后再单独处理行和列即可
代码
class Solution {
public:
void setZeroes(vector<vector<int>>& matrix) {
bool is_col = false; //此处我们让matrix[0][0]为行的标记,所以开了个标记列的bool变量
int row = matrix.size();
int column = matrix[0].size();
for(int i=0;i<row;i++){
if(matrix[i][0] == 0) is_col = true; //只要第一列有0,那么最后我们肯定要对第一列进行赋值为0的操作
for(int j=1;j<column;j++)
if(matrix[i][j] == 0){
matrix[0][j] = 0;
matrix[i][0] = 0;
} //标记行头、列头
}
for(int i=1;i<row;i++)
for(int j=1;j<column;j++)
if(matrix[i][0] == 0 || matrix[0][j] == 0)
matrix[i][j] = 0;
if(matrix[0][0] == 0)
for(int j=1;j<column;j++)
matrix[0][j] = 0;
if(is_col) //第一列为0
for(int i=0;i<row;i++)
matrix[i][0] = 0;
}
};
以上是关于Leetcode.面试题 01.08. Zero Matrix LCCI题解的主要内容,如果未能解决你的问题,请参考以下文章
LeetCode 1624. 两个相同字符之间的最长子字符串 / 698. 划分为k个相等的子集 / 面试题 01.08. 零矩阵 / 1694. 重新格式化电话号码