力扣第 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),符合题目要求。
相关推荐
hanlin03几秒前
刷题笔记:力扣第76题-最小覆盖子串
笔记·算法·leetcode
Zane19942 分钟前
比较排序跑不出O(nlogn)是数学上证明过的,计数、桶、基数排序凭什么能绕开这堵墙
算法·排序算法
tiger8653 分钟前
大语言模型面试和题解,梳理中国主流开源 LLM 系列的发展脉络、技术路线与工程取舍
人工智能·gpt·深度学习·算法·自然语言处理·面试·transformer
我不会起名字32216 分钟前
一天一道力扣Hot100(36):深度优先算法---组合总和
数据结构·c++·后端·python·算法·go
虚无的纽扣43 分钟前
【力扣刷题】第三天:有效三角形的个数、快乐数
算法·排序算法
tiger8651 小时前
大语言模型面试和题解,Context Engineering 怎么做?长 Prompt、动态上下文与 Memory 管理
人工智能·深度学习·算法·语言模型·自然语言处理·面试·nlp
不会就选b1 小时前
算法日常・每日刷题--<贪心>17
算法
随便发挥4 小时前
Leetcode 剑指 Offer II 186. 文物朝代判断
leetcode
6Hzlia4 小时前
【Classic 150 刷题计划】 LeetCode 205. 同构字符串 | C++ 双向绑定与哈希表映射
c++·算法·leetcode
有点。10 小时前
C++03阶段练习(练习题)
数据结构·算法·图论