力扣第 73 题 矩阵置零

题目描述

给定一个 m x n 的矩阵 matrix,其中每个元素不是 0 就是非零整数。

如果一个元素是 0,则将它所在的整行和整列都置为 0。请你实现这个操作,要求 空间复杂度 O(1)


示例

示例 1:

输入

matrix = [
  [1,1,1],
  [1,0,1],
  [1,1,1]
]

输出

[
  [1,0,1],
  [0,0,0],
  [1,0,1]
]

示例 2:

输入

matrix = [
  [0,1,2,0],
  [3,4,5,2],
  [1,3,1,5]
]

输出

[
  [0,0,0,0],
  [0,4,5,0],
  [0,3,1,0]
]

解题思路

1. 暴力法

  • 最直观的做法是,遍历整个矩阵,遇到 0 时,标记该位置所在的行和列,并将这些行和列的所有元素设置为 0。
  • 这种方法的空间复杂度是 O(m + n),因为我们需要额外的数组来记录需要置零的行和列。

2. 空间优化(O(1) 空间复杂度)

  • 题目要求空间复杂度是 O(1),即不能使用额外的数组(如布尔数组)来存储行和列的状态。我们可以在原地进行修改。
  • 通过使用矩阵的 第一行第一列 来记录该行和该列是否需要置零。
  • 第一行第一列 本身也可能包含零,所以需要额外的变量来记录它们是否需要置零。

3. 优化步骤

  1. 检查第一行和第一列:我们需要一个标志来记录第一行和第一列是否应该被置零。
  2. 遍历矩阵 :从矩阵的第二行和第二列开始,如果 matrix[i][j] == 0,就将 matrix[i][0]matrix[0][j] 设置为 0,表示该行和列应该被置零。
  3. 根据标志置零:根据第一行和第一列的标记,更新矩阵中的其它元素。
  4. 处理第一行和第一列:最后根据记录的标志更新第一行和第一列。

实现代码:

c 复制代码
#include <stdio.h>

void setZeroes(int** matrix, int matrixSize, int* matrixColSize) {
    int m = matrixSize; // 矩阵的行数
    int n = *matrixColSize; // 矩阵的列数

    int firstRowZero = 0, firstColZero = 0;

    // 检查第一行是否需要置零
    for (int j = 0; j < n; j++) {
        if (matrix[0][j] == 0) {
            firstRowZero = 1;
            break;
        }
    }

    // 检查第一列是否需要置零
    for (int i = 0; i < m; i++) {
        if (matrix[i][0] == 0) {
            firstColZero = 1;
            break;
        }
    }

    // 使用第一行和第一列标记其他行列需要置零
    for (int i = 1; i < m; i++) {
        for (int j = 1; j < n; j++) {
            if (matrix[i][j] == 0) {
                matrix[i][0] = 0; // 标记该行
                matrix[0][j] = 0; // 标记该列
            }
        }
    }

    // 根据标记的行列置零
    for (int i = 1; i < m; i++) {
        for (int j = 1; j < n; j++) {
            if (matrix[i][0] == 0 || matrix[0][j] == 0) {
                matrix[i][j] = 0;
            }
        }
    }

    // 处理第一行
    if (firstRowZero) {
        for (int j = 0; j < n; j++) {
            matrix[0][j] = 0;
        }
    }

    // 处理第一列
    if (firstColZero) {
        for (int i = 0; i < m; i++) {
            matrix[i][0] = 0;
        }
    }
}

int main() {
    int m = 3, n = 4;
    
    // 动态分配内存
    int** matrix = (int**)malloc(m * sizeof(int*));
    for (int i = 0; i < m; i++) {
        matrix[i] = (int*)malloc(n * sizeof(int));
    }

    // 初始化矩阵
    int matrixData[3][4] = {
        {0, 1, 2, 0},
        {3, 4, 5, 2},
        {1, 3, 1, 5}
    };

    // 将数据复制到动态分配的矩阵中
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            matrix[i][j] = matrixData[i][j];
        }
    }

    setZeroes(matrix, m, &n);

    // 打印结果
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            printf("%d ", matrix[i][j]);
        }
        printf("\n");
    }

    // 释放内存
    for (int i = 0; i < m; i++) {
        free(matrix[i]);
    }
    free(matrix);

    return 0;
}

步骤说明:

  1. 检查第一行和第一列是否需要置零:
    • 使用变量 firstRowZerofirstColZero 来分别标记第一行和第一列是否包含零。
  2. 遍历矩阵并标记需要置零的行和列:
    • 从第二行第二列开始,遍历矩阵。如果遇到 matrix[i][j] == 0,就将 matrix[i][0]matrix[0][j] 设置为零,表示第 i 行和第 j 列需要置零。
  3. 根据标记的行列更新矩阵:
    • 再次遍历矩阵,按照第一行和第一列的标记将相应位置的元素置零。
  4. 处理第一行和第一列:
    • 如果 firstRowZero 为 1,则将第一行所有元素置零。
    • 如果 firstColZero 为 1,则将第一列所有元素置零。

时间复杂度与空间复杂度

时间复杂度:

  • 遍历矩阵两次,因此时间复杂度是 O(m * n) ,其中 mn 分别是矩阵的行数和列数。

空间复杂度:

  • 我们仅使用了常量的额外空间(firstRowZerofirstColZero),因此空间复杂度是 O(1),符合题目要求。
相关推荐
九圣残炎21 分钟前
【从零开始的LeetCode-算法】3227. 字符串元音游戏
java·算法·leetcode
梁小憨憨1 小时前
变分推断(Variational Inference)
人工智能·算法·机器学习
就爱学编程1 小时前
重生之我在异世界学编程之C语言:选择结构与循环结构篇
c语言·数据结构·算法
一只大侠1 小时前
输入一串字符,以“?”结束。统计其中字母个数,数字个数,其它符号个数。:JAVA
java·开发语言·算法
winstongit1 小时前
捷联惯导原理和算法预备知识
算法·机器人
£suPerpanda2 小时前
P3916 图的遍历(Tarjan缩点和反向建边)
数据结构·c++·算法·深度优先·图论
IT古董2 小时前
【机器学习】机器学习的基本分类-监督学习-决策树-C4.5 算法
人工智能·学习·算法·决策树·机器学习·分类
m0_694938012 小时前
Leetcode打卡:棋盘上有效移动组合的数目
算法·leetcode·职场和发展
kitesxian2 小时前
Leetcode543. 二叉树的直径(HOT100)
算法·深度优先
我是博博啦2 小时前
matlab中disp,fprintf,sprintf,display,dlmwrite输出函数之间的区别
算法·matlab