当前位置: 首页 > news >正文

LeetCode热题100(Java)(6)矩阵

本章包括的题目有:

73. 矩阵置零 - 力扣(LeetCode)

54. 螺旋矩阵 - 力扣(LeetCode)

48. 旋转图像 - 力扣(LeetCode)

240. 搜索二维矩阵 II - 力扣(LeetCode)

1.矩阵置零

思路解析:

有一种简单的思路是创建一个矩阵,标记每个0元素的位置,然后在原矩阵上根据标出来的位置将其行和列置为0。显然,这种思路的空间复杂度是 O(mn) 。当然,我们可以对其进行优化,创建两个数组,在遍历原矩阵的过程中,分别将遍历到的0位置的横纵坐标分别存入对应数组中,由于可能会有相同的横纵坐标,所以我们这里用HashSet去重,可以适当的优化时间效率。

代码实现:

import java.util.ArrayList; import java.util.HashSet; import java.util.Set; class Solution { public void setZeroes(int[][] matrix) { Set<Integer> line = new HashSet<>(); Set<Integer> row = new HashSet<>(); for (int i = 0; i < matrix.length; i++) { for (int j = 0; j < matrix[0].length; j++) { if(matrix[i][j] == 0){ line.add(i); row.add(j); } } } for(Integer l : line){ for (int i = 0; i < matrix[0].length; i++) { matrix[l][i] = 0; } } for(Integer r : row){ for (int i = 0; i < matrix.length; i++) { matrix[i][r] = 0; } } } }

时间复杂度O(m*n)

空间复杂度O(m + n)

当然,我们也可以原地对其进行标记,得到空间复杂度为 O(1)的方法,可以先定义两个变量,看一下第一行和第一列是否需要被标记为0。然后遍历数组,若某个位置是0,则将其对应的行的第一个和列的第1个位置都标记为0,这样遍历完成之后,再通过第一行和第一列被标记为0的数据去调整整个数组。

如图所示,第一张为原数组,由于第一行有0,所以我们要用一个常量标记第一行,最终要全部置为0,然后将中间位置的0分别将其对应的行列的第一个位置标为0,这样在遍历行的时候,把行对应的所有列标记为0,遍历列的时候,把列对应的所有行标记为0,最后再看常量是否标记第一行和第一列,即可完成整个矩阵的置零操作。

2.螺旋矩阵

思路解析:

螺旋矩阵思路简单,但是代码的细节问题较多,笔者写的时候的思路是,先创建一个矩阵去表示当前位置的值是否被访问过。然后依次向左、向下、向右、向上循环,直到访问到边界,或者访问到被访问过的元素,依次访问完所有元素,即可得到答案。

代码实现:

class Solution { public List<Integer> spiralOrder(int[][] matrix) { int m = matrix.length; int n = matrix[0].length; ArrayList<Integer> ret = new ArrayList<>(); boolean[][] visited = new boolean[m][n]; int i = 0,j = 0; while(m * n != ret.size()){ while(j >= 0 && j < n && i >= 0 && i < m && !visited[i][j]){ ret.add(matrix[i][j]); visited[i][j] = true; j++; if(j >= n || visited[i][j]) { j--; i++; break; } } while(j >= 0 && j < n && i >= 0 && i < m && !visited[i][j]){ ret.add(matrix[i][j]); visited[i][j] = true; i++; if(i >= m || visited[i][j]) { i--; j--; break; } } while(j >= 0 && j < n && i >= 0 && i < m && !visited[i][j]){ ret.add(matrix[i][j]); visited[i][j] = true; j--; if(j < 0 || visited[i][j]) { j++; i--; break; } } while(j >= 0 && j < n && i >= 0 && i < m && !visited[i][j]){ ret.add(matrix[i][j]); visited[i][j] = true; i--; if(i < 0 || visited[i][j]) { i ++; j ++; break; } } } return ret; } }

但是这样写极容易出错,我们可以通过维护四个边界的方式,一步步缩小整个矩阵的搜索范围。维护四个边界:top, bottom, left, right,按顺序打印: 上行:从 left 到 right,然后 top++ ;右列:从 top 到 bottom,然后 right-- ;下行:从 right 到 left,然后 bottom-- ;左列:从 bottom 到 top,然后 left++

代码实现:

class Solution { public List<Integer> spiralOrder(int[][] matrix) { List<Integer> res = new ArrayList<>(); if (matrix.length == 0) return res; int top = 0, bottom = matrix.length - 1; int left = 0, right = matrix[0].length - 1; while (top <= bottom && left <= right) { for (int j = left; j <= right; j++) { res.add(matrix[top][j]); } top++; for (int i = top; i <= bottom; i++) { res.add(matrix[i][right]); } right--; if (top <= bottom) { for (int j = right; j >= left; j--) { res.add(matrix[bottom][j]); } bottom--; } if (left <= right) { for (int i = bottom; i >= top; i--) { res.add(matrix[i][left]); } left++; } } return res; } }

3.旋转图像

思路解析:

我们可以将矩阵层层转置,通过四角轮换的方式

代码实现:

class Solution { public void rotate(int[][] matrix) { int n = matrix.length; for (int i = 0; i < n / 2; i++) { for (int j = i; j < n - 1 - i; j++) { swap(i ,j, matrix); } } } private void swap(int i, int j, int[][] matrix) { //[i][j], [j][len - 1 - i], [len - 1 - i][len - 1 - j], [len - 1 - j][i] int n = matrix.length; int temp = matrix[i][j]; matrix[i][j] = matrix[n - 1 - j][i]; matrix[n - 1 - j][i] = matrix[n - 1 - i][n - 1 - j]; matrix[n - 1 - i][n - 1 - j] = matrix[j][n - 1 - i]; matrix[j][n - 1 - i] = temp; } }

时间复杂度O(n*n)

空间复杂度O(1)

拓展思路:

也可以通过转置加水平翻转的方式得到结果。先沿对角线将矩阵转置,然后将矩阵水平翻转,即可得到顺时针旋转的结果。

代码实现:

public void rotate(int[][] matrix) { int n = matrix.length; for (int i = 0; i < n; i++) { for (int j = i; j < n; j++) { int temp = matrix[i][j]; matrix[i][j] = matrix[j][i]; matrix[j][i] = temp; } } for (int i = 0; i < n; i++) { for (int j = 0; j < n / 2; j++) { int temp = matrix[i][j]; matrix[i][j] = matrix[i][n - 1 - j]; matrix[i][n - 1 - j] = temp; } } }

时间复杂度O(n*n)

空间复杂度O(1)

4.搜索二维矩阵

思路解析:

此题的关键在于我们要从右上角或者从左下角开始,这样的话,我们每次进行选择,就能排除掉一行或者一列。我们拿右上角举例,右上角如果往左走就是变小,往下走就是变大,可以通过对比当前值与目标值的大小,选择往下走或是往左走(类似二叉排序数)。

代码实现:

class Solution { public boolean searchMatrix(int[][] matrix, int target) { if (matrix == null || matrix.length == 0 || matrix[0].length == 0) return false; int m = matrix.length; int n = matrix[0].length; int i = 0, j = n - 1; // 从右上角开始 while (i < m && j >= 0) { if (matrix[i][j] == target) { return true; } else if (matrix[i][j] > target) { j--; // 当前值太大,排除当前列 } else { i++; // 当前值太小,排除当前行 } } return false; } }

时间复杂度O(m + n)

空间复杂度O(1)

上一章:

LeetCode热题100(Java)(5)普通数组-CSDN博客

下一章:

链表(上)

http://www.jsqmd.com/news/725463/

相关文章:

  • SketchUp STL插件终极指南:5步实现3D打印模型无缝转换
  • 3步实战:完全掌握ComfyUI Manager离线部署架构
  • 告别内卷 臻问GEO加盟让获客更简单 - 速递信息
  • 2026年天津代理记账公司品牌推荐 - 工业品牌热点
  • 基于Akari-Shard分布式架构的LCU工具集:高性能LeagueClient扩展解决方案
  • 2026年地面油污清洗剂:制造业清洁三大趋势解析 - 速递信息
  • 告别臃肿模拟器:Windows上运行安卓应用的终极轻量级方案
  • Windows平台原生APK解析技术深度解析与架构揭秘
  • 电泳涂装工艺生产企业哪家好? - 工业品牌热点
  • 冰淇淋品牌排名及优质品牌推荐,解锁夏日舌尖上的清凉盛宴
  • NoFences终极指南:免费开源工具彻底解决Windows桌面混乱问题
  • Arm GICv3中断控制器架构与关键寄存器解析
  • 如何快速配置英雄联盟全能自动化助手:LeagueAkari完整使用教程
  • 【YOLOv11】070、YOLOv11异常检测:正常数据训练下的异常目标识别
  • 龙威互动科技客服服务富通天下:北京打造数字化私域平台,赋能中国外贸品牌出海! - 速递信息
  • 如何快速掌握Android虚拟定位:FakeLocation终极使用指南
  • 正规外汇平台排行榜解析:合规与服务核心维度对比 - 速递信息
  • 网盘下载新时代:八大平台直链助手终极指南
  • 告别环境变量报错!JDK 20在Windows 11上的保姆级安装与配置全流程(含Notepad++联动)
  • 304L 不锈钢毛细管费用高吗?年创金属材料揭秘 - 工业推荐榜
  • NCM解密工具完全指南:3分钟解锁网易云音乐加密格式
  • ArchivePasswordTestTool:终极免费压缩包密码恢复工具完整指南
  • AMD Ryzen SMU调试工具:揭秘处理器底层参数调优的完整指南
  • FPGA设计避坑指南:为什么你的Mealy状态机输出有毛刺?输出寄存实战解析
  • 终极Gofile下载加速方案:告别龟速,体验多线程高速下载
  • 终极Spyder配置指南:快速搭建Python科学计算开发环境
  • 探索三维互联网:Firefox Reality如何重新定义VR/AR浏览体验
  • 生态学与GIS入门:手把手教你下载和处理MODIS NPP数据(以中国区域为例)
  • 用Python和OpenCV玩转色彩空间:从RGB到YCbCr的保姆级实战(附完整代码)
  • 为什么所有编译都需要./configure, make, make install?