LeetCode题目73:矩阵置零

作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。
会一些的技术:数据分析、算法、SQL、大数据相关、python
欢迎加入社区:码上找工作
作者专栏每日更新:
LeetCode解锁1000题: 打怪升级之旅
python数据分析可视化:企业实战案例
python源码解读
备注说明:方便大家阅读,统一使用python,带必要注释,公众号 数据分析螺丝钉 一起打怪升级

题目描述

给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。

输入格式
  • matrix:一个二维整数数组。
输出格式
  • 不返回任何内容,但要将 matrix 中的行和列置零。

示例

示例 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. 标记零的位置:遍历整个矩阵,使用两个集合来分别记录哪些行和哪些列需要被置零。
  2. 置零行和列:再次遍历矩阵,根据行和列的集合来置零对应的行和列。
完整的规范代码
def setZeroes(matrix):
    """
    使用额外存储空间的方法来置零矩阵
    :param matrix: List[List[int]], 输入的二维矩阵
    """
    rows, cols = set(), set()
    m, n = len(matrix), len(matrix[0])
    for i in range(m):
        for j in range(n):
            if matrix[i][j] == 0:
                rows.add(i)
                cols.add(j)

    for i in range(m):
        for j in range(n):
            if i in rows or j in cols:
                matrix[i][j] = 0

# 示例调用
matrix = [
    [1,1,1],
    [1,0,1],
    [1,1,1]
]
setZeroes(matrix)
print(matrix)  # 输出: [[1,0,1],[0,0,0],[1,0,1]]
算法分析
  • 时间复杂度:(O(m * n)),需要两次遍历整个矩阵。
  • 空间复杂度:(O(m + n)),使用了额外空间来存储需要置零的行和列。

方法二:使用常数空间的优化

解题步骤
  1. 原地修改:使用矩阵的第一行和第一列来记录该行或列是否需要置零。
  2. 单独标记第一行和第一列:因为第一行和第一列共用 matrix[0][0],所以需要一个额外的标记来区分第一列是否需要置零。
  3. 二次遍历填充:第一次从底部开始遍历以避免提前修改第一行或第一列的值,第二次从顶部开始正常遍历并使用第一行和第一列的标记来置零。
完整的规范代码
def setZeroes(matrix):
    """
    使用常数空间的方法来置零矩阵
    :param matrix: List[List[int]], 输入的二维矩阵
    """
    m, n = len(matrix), len(matrix[0])
    first_col = any(matrix[i][0] == 0 for i in range(m))
    for i in range(m):
        for j in range(1, n):  # 从第二列开始
            if matrix[i][j] == 0:
                matrix[i][0] = matrix[0][j] = 0

    for i in range(m - 1, -1, -1):
        for j in range(1, n):
            if matrix[i][0] == 0 or matrix[0][j] == 0:
                matrix[i][j] = 0
        if first_col:
            matrix[i][0] = 0

# 示例调用
matrix = [
    [0,1,2,0],
    [3,4,5,2],
    [1,3,1,5]
]
setZeroes(matrix)
print(matrix)  # 输出: [[0,0,0,0],[0,4,5,0],[0,3,1,0]]
算法分析
  • 时间复杂度:(O(m * n)),两次遍历整个矩阵。
  • 空间复杂度:(O(1)),除了几个用于标记的变量外,没有使用额外的空间。

方法三:改进的标记方法

解题步骤
  1. 单次遍历:在第一次遍历的同时,直接在第一行和第一列上进行标记。
  2. 尾部处理:利用第一行和第一列的标记进行最后的置零处理。
完整的规范代码
def setZeroes(matrix):
    """
    改进的标记方法来置零矩阵
    :param matrix: List[List[int]], 输入的二维矩阵
    """
    m, n = len(matrix), len(matrix[0])
    for i in range(m):
        if matrix[i][0] == 0:
            first_col_zero = True
        for j in range(1, n):
            if matrix[i][j] == 0:
                matrix[i][0] = matrix[0][j] = 0

    for i in range(m - 1, -1, -1):
        for j in range(n - 1, 0, -1):
            if matrix[i][0] == 0 or matrix[0][j] == 0:
                matrix[i][j] = 0
        if first_col_zero:
            matrix[i][0] = 0

# 示例调用
matrix = [
    [1,1,1],
    [1,0,1],
    [1,1,1]
]
setZeroes(matrix)
print(matrix)  # 输出: [[1,0,1],[0,0,0],[1,0,1]]
算法分析
  • 时间复杂度:(O(m * n)),只有一次遍历,但每个元素都被检查。
  • 空间复杂度:(O(1)),使用了原矩阵的第一行和第一列作为标记,没有额外空间。

方法四:首尾标记优化

解题步骤
  1. 首尾行列标记:分别使用矩阵的首行和尾行进行置零标记。
  2. 中间处理:根据首尾标记决定中间行列是否需要置零。
完整的规范代码
def setZeroes(matrix):
    """
    首尾标记优化方法来置零矩阵
    :param matrix: List[List[int]], 输入的二维矩阵
    """
    m, n = len(matrix), len(matrix[0])
    first_row_zero = any(matrix[0][j] == 0 for j in range(n))
    last_row_zero = any(matrix[m-1][j] == 0 for j in range(n))

    for i in range(1, m-1):
        for j in range(1, n-1):
            if matrix[i][j] == 0:
                matrix[i][0] = matrix[0][j] = 0

    for i in range(1, m-1):
        for j in range(1, n-1):
            if matrix[i][0] == 0 or matrix[0][j] == 0:
                matrix[i][j] = 0

    if first_row_zero:
        for j in range(n):
            matrix[0][j] = 0
    if last_row_zero:
        for j in range(n):
            matrix[m-1][j] = 0

# 示例调用
matrix = [
    [1,1,1],
    [1,0,1],
    [1,1,1]
]
setZeroes(matrix)
print(matrix)  # 输出: [[1,0,1],[0,0,0],[1,0,1]]
算法分析
  • 时间复杂度:(O(m * n)),通过两次遍历完成。
  • 空间复杂度:(O(1)),使用首尾行列作为标记,不需要额外空间。

方法五:位运算标记法

解题步骤
  1. 使用位运算标记:通过位运算标记哪些行和列需要置零。
  2. 处理置零:根据标记,决定如何置零矩阵中的行和列。
完整的规范代码
def setZeroes(matrix):
    """
    位运算标记法来置零矩阵
    :param matrix: List[List[int]], 输入的二维矩阵
    """
    row_flag, col_flag = 0, 0
    m, n = len(matrix), len(matrix[0])
    for i in range(m):
        for j in range(n):
            if matrix[i][j] == 0:
                row_flag |= (1 << i)
                col_flag |= (1 << j)

    for i in range(m):
        for j in range(n):
            if row_flag & (1 << i) or col_flag & (1 << j):
                matrix[i][j] = 0

# 示例调用
matrix = [
    [1,1,1],
    [1,0,1],
    [1,1,1]
]
setZeroes(matrix)
print(matrix)  # 输出: [[1,0,1],[0,0,0],[1,0,1]]
算法分析
  • 时间复杂度:(O(m * n)),必须遍历整个矩阵来标记和处理。
  • 空间复杂度:(O(1)),使用固定数量的位标记。

不同算法的优劣势对比

特征方法一:额外存储方法二:常数空间优化方法三:改进标记方法四:首尾标记优化方法五:位运算标记
时间复杂度(O(m * n))(O(m * n))(O(m * n))(O(m * n))(O(m * n))
空间复杂度(O(m + n))(O(1))(O(1))(O(1))(O(1))
优势简单直观空间高效一次遍历即可特殊行列单独处理位操作快速且节省空间
劣势空间占用较大需要复杂的标记逻辑实现稍复杂实现稍复杂对位操作要求较高,可能增加实现复杂性

应用示例

图像处理:在图像处理中,可能需要对图像矩阵进行操作,类似于置零的操作可用于快速清除某些区域。

数据清洗:在数据预处理阶段,需要将包含无效数据的行和列清除,这些算法可直接应用于清洗包含缺失值的数据集。

软件开发:在软件开发中,处理大规模数据时常需要类似的矩阵操作来快速应用某些条件,这些方法提供了多种实现这一功能的方式。

  • 24
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

数据分析螺丝钉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值