运行结果
执行结果:通过
执行用时 :2 ms, 在所有 Java 提交中击败了55.24%的用户
内存消耗 :47.8 MB, 在所有 Java 提交中击败了87.63%的用户
代码与注释
class Solution {
public void setZeroes(int[][] matrix) {
int R = matrix.length; // 行长度
int C = matrix[0].length; // 列长度
boolean zeroCol = false;
// 做标记
for (int i = 0; i < R; i++)
{
if (matrix[i][0] == 0) zeroCol = true; // 判断首列是否有零
for (int j = 1; j < C; j++)
{
if (matrix[i][j] == 0)
{
matrix[i][0] = 0; // 行标记
matrix[0][j] = 0; // 列标记
}
}
}
// 根据标记写0
for (int i = 1; i < R; i++)
{
for (int j = 1; j < C; j++)
{
if (matrix[i][0] == 0 || matrix[0][j] == 0)
{
matrix[i][j] = 0;
}
}
}
// 最后处理零行
if (matrix[0][0] == 0)
{
for (int j = 0; j < C; j++) matrix[0][j] = 0;
}
// 最后处理零列
if (zeroCol)
{
for (int i = 0; i < R; i++) matrix[i][0] = 0;
}
}
}
做题体会
- 题目要求使用原地算法,空间复杂度为O(1),那么需要直接修改原矩阵。
- 一个mxn的矩阵,遍历时间复杂度至少的情况为O(m*n)。
- 基本想法是,遍历矩阵,当出现零时,在其对应的行、列的首位,置零标识,根据该标识将对应的行列置零即可。这个做法的好处是,标识占用的空间是原数组空间,且标识置位与m或n的长度无关,无需额外的时间复杂度。
- 该算法的时间复杂度为O(m*n),空间复杂度为O(1)。
- 需要注意的是,数组零零位置为零,表示零行需要置零,零列置零需要额外的标志位zeroCol。
- 当遍历整个数组,进行置零操作时,最后处理零行和零列,防止标识丢失。
- 有另一种类似的算法,空间复杂度也为O(1),区别在于,遍历整个矩阵找到零时,将该零所在的行、列除零外的数置为一个极小负值,最后出现该极小负值的所有位置置零即可,因为在遍历整个数组的基础上,还需要额外遍历行列,做标识,所以该算法的时间复杂度为O((m*n)x(m+n))。
算法二
运行结果
执行结果:通过
执行用时 :5 ms, 在所有 Java 提交中击败了17.32%的用户
内存消耗 :43.6 MB, 在所有 Java 提交中击败了97.32%的用户
代码与注释
class Solution {
public void setZeroes(int[][] matrix) {
int R = matrix.length; // 行长度
int C = matrix[0].length; // 列长度
Set<Integer> row = new HashSet<Integer>();
Set<Integer> col = new HashSet<Integer>();
// 记录需置零的行号和列号
for (int i = 0; i < R; i++)
{
for (int j = 0; j < C; j++)
{
if (matrix[i][j] == 0)
{
row.add(i);
col.add(j);
}
}
}
// 查询hash表,置零
for (int i = 0; i < R; i++)
{
for (int j = 0; j < C; j++)
{
if (row.contains(i) || col.contains(j))
{
matrix[i][j] = 0;
}
}
}
}
}
做题体会
- 时间复杂度为O(mxn),空间复杂度为O(m+n)。
- 需要额外的空间,存储需要置零的行号和列号,采用的hash表,查询比较高效。