LeetCode 热题 100 之 73.矩阵置零(含图解)

官方原始解法(容易想到)

复制代码
class Solution {
    public void setZeroes(int[][] matrix) {
        int m = matrix.length, n = matrix[0].length;
        boolean[] row = new boolean[m];
        boolean[] col = new boolean[n];
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (matrix[i][j] == 0) {
                    row[i] = col[j] = true;
                }
            }
        }
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (row[i] || col[j]) {
                    matrix[i][j] = 0;
                }
            }
        }
    }
}

作者:力扣官方题解
链接:https://leetcode.cn/problems/set-matrix-zeroes/solutions/669901/ju-zhen-zhi-ling-by-leetcode-solution-9ll7/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

为了在不使用额外空间的情况下解决问题,我们可以利用矩阵的第一行和第一列作为标记,来记录哪些行和列需要被置零。同时,使用两个额外的布尔变量来记录第一行和第一列本身是否需要置零。


步骤分解

  1. 预处理标记

    • 遍历矩阵,检查第一行和第一列是否存在 0,并用 row0col0 两个布尔变量记录下来。
    • 再次遍历矩阵(从第二行第二列开始),如果发现 matrix[i][j] == 0,则将 matrix[i][0](标记第 i 行)和 matrix[0][j](标记第 j 列)置为 0。
  2. 置零操作

    • 遍历矩阵(从第二行第二列开始),如果 matrix[i][0]matrix[0][j] 为 0,则将 matrix[i][j] 置为 0。
    • 根据预处理的 row0col0 标记,最后决定是否将第一行和第一列整体置零。

画的丑请见谅


Java 代码实现

复制代码
public void setZeroes(int[][] matrix) {
    int m = matrix.length;
    int n = matrix[0].length;
    boolean row0 = false; // 标记第一行是否有0
    boolean col0 = false; // 标记第一列是否有0

    // 1. 检查第一行和第一列
    for (int j = 0; j < n; j++) {
        if (matrix[0][j] == 0) {
            row0 = true;
            break;
        }
    }
    for (int i = 0; i < m; i++) {
        if (matrix[i][0] == 0) {
            col0 = true;
            break;
        }
    }

    // 2. 用第一行和第一列标记需要置零的行和列
    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;
            }
        }
    }

    // 3. 根据标记置零(除第一行第一列外)
    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;
            }
        }
    }

    // 4. 最后处理第一行和第一列
    if (row0) {
        for (int j = 0; j < n; j++) {
            matrix[0][j] = 0;
        }
    }
    if (col0) {
        for (int i = 0; i < m; i++) {
            matrix[i][0] = 0;
        }
    }
}

复杂度分析

  • 时间复杂度:O (mn),我们对矩阵进行了多次线性遍历。
  • 空间复杂度:O (1),我们只使用了常数级别的额外空间,符合题目 "原地算法" 的要求。

这个算法的核心作用,是在不额外占用大量内存的前提下,高效地对矩阵进行 "置零" 操作,它的价值主要体现在以下几个方面:


实际作用

1. 核心作用:原地修改,节省空间

  • 空间效率:它通过复用矩阵的第一行和第一列作为 "标记位",将空间复杂度从 O (mn) 或 O (m+n) 优化到了 O (1),只使用了两个布尔变量。
  • 原地修改:直接在输入矩阵上进行修改,避免了创建一个同样大小的新矩阵,这在处理大规模数据(如高清图像、传感器矩阵、大型表格)时至关重要。

2. 典型应用场景

图像处理与计算机视觉 🖼️
  • 图像降噪 / 二值化:在处理图像矩阵时,经常需要将满足特定条件(如亮度低于阈值)的像素所在行 / 列置零。这个算法可以高效地完成这类任务,同时保持内存占用极低。
  • 特征提取:在边缘检测或特征点提取后,需要将无关的背景区域(行 / 列)清零,以突出主体。
数据清洗与预处理 📊
  • 缺失值处理:在数据分析中,矩阵中的 0 可以代表缺失值。这个算法可以快速地将包含缺失值的行和列标记并清除,为后续的机器学习模型准备干净的数据。
  • 稀疏矩阵优化:在处理稀疏矩阵时,可以通过此算法快速清理掉全零行 / 列,减少存储和计算开销。
游戏与图形学 🎮
  • 碰撞检测:在游戏开发中,矩阵可以表示游戏世界的网格。当检测到碰撞(某个元素为 0)时,需要将其所在的行和列(如障碍物)置零,以更新游戏状态。
  • 渲染优化:在 3D 渲染中,通过置零不可见的行 / 列来优化渲染管线,减少不必要的计算。
传感器与物联网 📡
  • 传感器数据过滤:在物联网设备中,矩阵可以存储来自多个传感器的时间序列数据。当某个传感器(行)或某个时间点(列)的数据异常(为 0)时,需要将其置零,以避免影响整体分析。

3. 设计思想的复用价值

这个算法体现的 "用已有空间做标记,避免额外开销" 的思想,在很多领域都有借鉴意义:

  • 内存受限系统:如嵌入式设备、移动应用,内存资源非常宝贵,任何能节省空间的技巧都至关重要。
  • 大数据处理:在分布式计算框架中,减少数据的复制和传输是提升性能的关键。
相关推荐
0 0 02 小时前
CCF-CSP 34-2 矩阵重塑(其二)(reshape2)【C++】考点:矩阵转置模拟
开发语言·c++·算法·矩阵
AI科技星19 小时前
时空的几何本源与物理现象的建构:论统一场论的宇宙二元论与观察者中心范式
人工智能·线性代数·算法·矩阵·数据挖掘
汉克老师20 小时前
GESP2024年3月认证C++二级( 第三部分编程题(2)小杨的日字矩阵 )
c++·矩阵·循环结构·gesp二级·gesp2级·打印图形
样例过了就是过了20 小时前
LeetCode热题100 螺旋矩阵
算法·leetcode·矩阵
样例过了就是过了1 天前
LeetCode热题100 矩阵置零
算法·leetcode·矩阵
じ☆冷颜〃2 天前
从确定性算子到随机生成元:谱范式的演进
经验分享·笔记·线性代数·矩阵·抽象代数
狮子座明仔2 天前
Agent World Model:给智能体造一个“矩阵世界“——无限合成环境驱动的强化学习
人工智能·线性代数·语言模型·矩阵
民乐团扒谱机4 天前
【硬科普】位置与动量为什么是傅里叶变换对?从正则对易关系到时空弯曲,一次讲透
人工智能·线性代数·正则·量子力学·傅里叶变换·对易算符
jz_ddk4 天前
[数学基础] 浅尝矩阵基础运算
人工智能·线性代数·ai·矩阵