从扫雷游戏到矩阵操作:探索矩阵置零问题

生活中的算法

想象你在玩扫雷游戏,当你点到一个地雷时,不仅这个格子会被标记,与它同行同列的格子也都会受到影响。或者想象一个办公室的座位表,如果某个位置发现了感染者,为了安全起见,需要将该员工所在的整行(同排同事)和整列(对面同事)都标记为密切接触者需要检测。

这种"一点触发,全行全列响应"的场景在生活中很常见:

  • 学校课程表中,如果某个老师请假,那一整行的课程都需要调整
  • 表格处理软件中,调整某个单元格的格式,可以统一设置整行整列
  • 影院选座系统中,如果一个座位损坏,可能需要锁定那一排和那一列的预订功能

问题描述

LeetCode第73题"矩阵置零"是这样描述的:给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0。请使用原地算法。

例如:

输入:matrix = [
[1,1,1],
[1,0,1],
[1,1,1]
]
输出:[
[1,0,1],
[0,0,0],
[1,0,1]
]

最直观的解法:额外空间标记

就像在处理办公室防疫时,先用一张新表记录下所有需要检测的位置,然后统一处理。

让我们用一个简单的例子来理解:

原矩阵:
[1,2,0]
[3,4,5] 1. 记录0所在的位置:
- 第0行,第2列有个0 2. 标记需要置零的行和列:
- 需要置零的行:[0]
- 需要置零的列:[2] 3. 根据记录修改矩阵:
[0,0,0] // 第0行全置零
[3,4,0] // 第2列置零

优化解法:原地标记

仔细思考会发现,我们可以用矩阵的第一行和第一列来记录标记信息,就像用办公室的墙上的记事板来标记需要处理的区域。这样就不需要额外的空间了。

原地标记的原理

  1. 先记录第一行和第一列是否原本包含0
  2. 用第一行和第一列作为标记板
  3. 处理剩余的矩阵
  4. 最后根据第一步的记录处理第一行和第一列

示例演示

用下面的矩阵来说明:

[1,2,3]
[4,0,6]
[7,8,9] 1. 记录第一行和第一列的状态:
- 第一行没有0
- 第一列没有0 2. 用第一行和第一列标记:
- 因为matrix[1][1]=0,所以:
- 标记第一行:matrix[0][1]=0
- 标记第一列:matrix[1][0]=0 3. 根据标记处理矩阵主体:
[1,0,3]
[0,0,0]
[7,0,9] 4. 最后根据第一步的记录处理第一行第一列

Java代码实现

public void setZeroes(int[][] matrix) {
if (matrix == null || matrix.length == 0) return; int m = matrix.length;
int n = matrix[0].length; // 记录第一行和第一列是否原本包含0
boolean firstRowHasZero = false;
boolean firstColHasZero = false; // 检查第一行
for (int j = 0; j < n; j++) {
if (matrix[0][j] == 0) {
firstRowHasZero = true;
break;
}
} // 检查第一列
for (int i = 0; i < m; i++) {
if (matrix[i][0] == 0) {
firstColHasZero = true;
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 (firstRowHasZero) {
for (int j = 0; j < n; j++) {
matrix[0][j] = 0;
}
} // 处理第一列
if (firstColHasZero) {
for (int i = 0; i < m; i++) {
matrix[i][0] = 0;
}
}
}

解法比较

让我们比较这两种方法:

额外空间标记:

  • 时间复杂度:O(m×n)
  • 空间复杂度:O(m+n)
  • 优点:思路清晰,实现简单
  • 缺点:需要额外空间

原地标记:

  • 时间复杂度:O(m×n)
  • 空间复杂度:O(1)
  • 优点:不需要额外空间
  • 缺点:实现稍复杂,需要额外记录第一行列的状态

解题技巧总结

这道题给我们的启发:

  1. 矩阵问题中,往往可以利用矩阵本身来存储信息
  2. 处理特殊情况(如第一行列)时,可以单独考虑
  3. 分步骤处理复杂问题可以让思路更清晰
  4. 在修改数据时,注意保护原始信息

类似的问题还有:

  • 生命游戏
  • 旋转图像
  • 岛屿数量

小结

通过矩阵置零这道题,我们学会了如何巧妙地利用矩阵本身来存储信息,避免使用额外空间。这种思维方式不仅适用于本题,在处理需要原地修改数据的矩阵问题时都很有启发。记住,当遇到需要在矩阵中标记信息的问题时,考虑能否利用矩阵本身的某些位置来存储标记!


作者:忍者算法

公众号:忍者算法

我准备了一份刷题清单,以及这些题目的详细题解,覆盖了绝大部分常见面试题。我可以很负责任地说,只要你把这些题真正掌握了,80%的算法面试都能遇到相似题目。公众号回复【刷题清单】获取~

完整GitHub项目

【忍者算法】从扫雷游戏到矩阵操作:探索矩阵置零问题|LeetCode 73 矩阵置零的更多相关文章

  1. C++算法代码——扫雷游戏

    题目来自:http://218.5.5.242:9018/JudgeOnline/problem.php?id=1685 题目描述 扫雷游戏是一款十分经典的单机小游戏. 在 n 行 m 列的雷区中有一 ...

  2. Java实现 LeetCode 73 矩阵置零

    73. 矩阵置零 给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0.请使用原地算法. 示例 1: 输入: [ [1,1,1], [1,0,1], [1,1,1] ...

  3. leetcode 73 矩阵置零 Python

    矩阵置零     给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0.请使用原地算法. 示例 1: 输入: [   [1,1,1],   [1,0,1],   [1 ...

  4. LeetCode 73. 矩阵置零(Set Matrix Zeroes)

    题目描述 给定一个 m x n 的矩阵,如果一个元素为 0,则将其所在行和列的所有元素都设为 0.请使用原地算法. 示例 1: 输入: [   [1,1,1],   [1,0,1],   [1,1,1 ...

  5. Leetcode之广度优先搜索(BFS)专题-529. 扫雷游戏(Minesweeper)

    Leetcode之广度优先搜索(BFS)专题-529. 扫雷游戏(Minesweeper) BFS入门详解:Leetcode之广度优先搜索(BFS)专题-429. N叉树的层序遍历(N-ary Tre ...

  6. 【Android】自己动手做个扫雷游戏

    1. 游戏规则 扫雷是玩法极其简单的小游戏,点击玩家认为不存在雷的区域,标记出全部地雷所在的区域,即可获得胜利.当点击不包含雷的块的时候,可能它底下存在一个数,也可能是一个空白块.当点击中有数字的块时 ...

  7. Java实现 蓝桥杯VIP 算法提高 扫雷

    算法提高 扫雷 时间限制:1.0s 内存限制:256.0MB 问题描述 扫雷游戏你一定玩过吧!现在给你若干个n×m的地雷阵,请你计算出每个矩阵中每个单元格相邻单元格内地雷的个数,每个单元格最多有8个相 ...

  8. C#编写扫雷游戏

    翻看了下以前大学学习的一些小项目,突然发现有个项目比较有意思,觉得有必要把它分享出来.当然现在看来,里面有很多的不足之处,但因博主现在已经工作,没有时间再去优化.这个项目就是利用C#编写一个Windo ...

  9. [Swift]LeetCode529. 扫雷游戏 | Minesweeper

    Let's play the minesweeper game (Wikipedia, online game)! You are given a 2D char matrix representin ...

  10. FZU OJ 1056 :扫雷游戏

    Problem 1056 扫雷游戏 Accept: 2624    Submit: 6903Time Limit: 1000 mSec    Memory Limit : 32768 KB  Prob ...

随机推荐

  1. JAVA MemCache 史无前例的详细讲解!看完包精通MEMCACHE!

    Memcach什么是Memcache Memcache集群环境下缓存解决方案 Memcache是一个高性能的分布式的内存对象缓存系统,通过在内存里维护一个统一的巨大的hash表,它能够用来存储各种格式 ...

  2. pycharm之debugger使用

    1.未打断点运程序,输出全部结果 2.打断点后,点击debug,代码执行到断点前停止(断点所在行不执行) 3.step over,是在单步执行时,在函数内遇到子函数时不会进入子函数内单步执行,而是将子 ...

  3. 序列化-serialVersionUID作用

    Serializable接口 作用:标记一个类可以被序列化,如果没有实现该接口,则会抛出异常. ObjectOutputStream中源码: 实验: serialVersionUID 作用:表示一个序 ...

  4. 中电金信鲸Bot RPA荣获最佳人工智能解决方案

    近年来,数字经济已成为国家"十四五"规划和"新基建"战略的重要支撑.银行业作为我国经济体系的重要组成部分,其发展战略也出现了新的变化.数字化智能化转型成为银行业 ...

  5. Linux NAS存储、文件共享

    Linux NAS存储之CIFS CIFS是Windows和Unix系统之间共享文件的一种协议,客户端通常是Windwos等.支持多节点同时挂载以及并发写入 1.服务器端操作(存储端) 1.1.服务器 ...

  6. Llama 3.2 900亿参数视觉多模态大模型本地部署及案例展示

    Llama 3.2 900亿参数视觉多模态大模型本地部署及案例展示 本文将介绍如何在本地部署Llama 3.2 90B(900亿参数)视觉多模态大模型,并开发一些Use Case,展示其强大的视觉理解 ...

  7. 利用shell中awk和xargs以及sed将多行多列文本中某一列合并成一行

    一.问题描述最近需要利用Shell将多行多列文本中某一列,通过指定的分隔符合并成一行.假设需要处理的文本如下: 我们主要处理的是,将用户名提取处理,合并成一行,并通过逗号进行分隔.最终的格式如下: & ...

  8. Qt编写地图综合应用48-地球模式、三维模式、地铁模式

    一.前言 百度地图本身提供了普通模式.地球模式.三维模式.地铁模式等好多种,普通模式是最常用的默认的,就是那个街道图和卫星图的,而地球模式和三维模式是最近几年才新增加的,为了迎合现在越来越多的用户的需 ...

  9. 基于Netty的IM聊天加密技术学习:一文理清常见的加密概念、术语等

    1.引言 在社区中,分享了很多篇基于Netty编写的IM聊天入门文章(比如<跟着源码学IM>系列.<基于Netty,从零开发IM>系列等),在这些文章中分享了各种IM通信算法原 ...

  10. spark (五) RDD的创建 & 分区

    目录 1. RDD的创建方式 1.1 从内存创建RDD 1.2 从外部存储(文件)创建RDD 1.3 从其他的RDD创建 1.4 直接 new RDD 2. 分区(partition) 2.1 mak ...