力扣第 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),符合题目要求。
相关推荐
cheems95275 分钟前
[算法手记] 贪心 爬楼梯问题
算法·贪心算法
KaMeidebaby17 分钟前
卡梅德生物技术快报|酵母双杂交 cDNA 文库构建与蛋白互作筛选流程
服务器·前端·数据库·人工智能·算法
圣保罗的大教堂24 分钟前
leetcode 3300. 替换为数位和以后的最小元素 简单
leetcode
sheeta199826 分钟前
LeetCode 每日一题笔记 日期:2026.05.27 题目:3121. 统计特殊字母的数量 II
笔记·算法·leetcode
ST——Jess36 分钟前
年度行业趋势研究报告:泛心理数字化赛道“流日推演”的算法困境与高保真交互范式重构
人工智能·算法·架构
Tisfy38 分钟前
LeetCode 3300.替换为数位和以后的最小元素:一次遍历
数学·算法·leetcode·模拟
garmin Chen1 小时前
LeetcodeHot100打卡(14、合并空间,15、轮转数组,16、除了自身以外数组乘积,17.缺失的第一个整数)
java·笔记·学习·算法
elseif1231 小时前
【C++】vector 详细版
开发语言·c++·算法
变量未定义~1 小时前
既约分数、阶乘约数、逆元、最大质因子个数【算法赛】
算法