LeetCode 热题 100 之 54.螺旋矩阵

LeetCode 热题 100 之 54.螺旋矩阵

解题思路(边界模拟法)

我们可以通过维护四个边界(上、下、左、右)来模拟顺时针螺旋遍历的过程:

  1. 从左到右遍历当前上边界的行,然后上边界向下移动。
  2. 从上到下遍历当前右边界的列,然后右边界向左移动。
  3. 如果上下边界仍有未遍历的行,则从右到左遍历当前下边界的行,然后下边界向上移动。
  4. 如果左右边界仍有未遍历的列,则从下到上遍历当前左边界的列,然后左边界向右移动。
  5. 重复以上步骤,直到所有边界交叉,遍历结束。

Java 代码实现

public class Solution { public List<Integer> spiralOrder(int[][] matrix) { List<Integer> res = new ArrayList<>(); if (matrix == null || matrix.length == 0) { return res; } int top = 0; int bottom = matrix.length - 1; int left = 0; int right = matrix[0].length - 1; while (top <= bottom && left <= right) { // 1. 从左到右遍历上边界 for (int j = left; j <= right; j++) { res.add(matrix[top][j]); } top++; // 2. 从上到下遍历右边界 for (int i = top; i <= bottom; i++) { res.add(matrix[i][right]); } right--; // 3. 如果还有行,从右到左遍历下边界 if (top <= bottom) { for (int j = right; j >= left; j--) { res.add(matrix[bottom][j]); } bottom--; } // 4. 如果还有列,从下到上遍历左边界 if (left <= right) { for (int i = bottom; i >= top; i--) { res.add(matrix[i][left]); } left++; } } return res; } } 

复杂度分析

  • 时间复杂度:O (mn),矩阵中的每个元素都被访问一次。
  • 空间复杂度:O (1),除了存储结果的列表外,我们只使用了常数级别的额外空间。

官方解法

class Solution { public List<Integer> spiralOrder(int[][] matrix) { // 1. 初始化结果列表,用于存储螺旋遍历的元素 List<Integer> order = new ArrayList<Integer>(); // 2. 边界校验:如果矩阵为空/行数为0/列数为0,直接返回空列表 if (matrix == null || matrix.length == 0 || matrix[0].length == 0) { return order; } // 3. 定义基础变量 int rows = matrix.length; // 矩阵的行数 int columns = matrix[0].length; // 矩阵的列数 boolean[][] visited = new boolean[rows][columns]; // 标记矩阵元素是否被访问过(避免重复遍历) int total = rows * columns; // 矩阵总元素数(遍历终止条件) int row = 0, column = 0; // 当前遍历的行、列坐标(初始在左上角) // 4. 定义四个移动方向:右(0,1)、下(1,0)、左(0,-1)、上(-1,0)(顺时针顺序) int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; int directionIndex = 0; // 当前方向的索引(初始为“右”) // 5. 遍历所有元素(循环total次) for (int i = 0; i < total; i++) { // 5.1 将当前元素加入结果列表,并标记为已访问 order.add(matrix[row][column]); visited[row][column] = true; // 5.2 计算下一个位置的坐标(按当前方向前进) int nextRow = row + directions[directionIndex][0]; int nextColumn = column + directions[directionIndex][1]; // 5.3 检查下一个位置是否合法:越界 或 已访问 → 需要切换方向 if (nextRow < 0 || nextRow >= rows || nextColumn < 0 || nextColumn >= columns || visited[nextRow][nextColumn]) { directionIndex = (directionIndex + 1) % 4; // 切换方向(取模4保证循环) } // 5.4 更新当前坐标(按新方向/原方向前进) row += directions[directionIndex][0]; column += directions[directionIndex][1]; } // 6. 返回遍历结果 return order; } }

扩展

一、核心应用场景

1. 图形 / 图像处理领域(最常见)
  • 场景:在图像编辑、计算机视觉中,经常需要按螺旋顺序处理像素(比如对图像局部区域做模糊、锐化、边缘检测,或提取特定区域的像素特征)。
    • 举例:
      • 对一张照片的某个矩形区域,从外到内螺旋式调整像素亮度 / 对比度,实现 “渐变晕影” 效果;
      • 医学影像(如 CT、MRI 切片)分析中,螺旋遍历病灶区域的像素,提取纹理特征辅助诊断。
  • 为什么用螺旋遍历:相比逐行 / 逐列遍历,螺旋遍历能更贴合 “从外围到核心” 的分析逻辑,比如先分析病灶边缘,再深入核心区域。
2. 数据可视化 / UI 交互
  • 场景:前端 / 移动端的可视化组件开发中,螺旋布局的图表、动画效果需要基于螺旋遍历的逻辑实现。
    • 举例:
      • 螺旋式排列的数字仪表盘、进度条(比如电商平台的 “销量螺旋增长” 可视化图表);
      • 游戏开发中,敌人从外围螺旋式向玩家角色移动的路径规划(本质是按螺旋顺序遍历二维地图坐标)。
3. 矩阵数据处理 / 算法题解(工程 + 面试)
  • 场景:后端数据处理中,对二维结构化数据(如表格、矩阵型传感器数据)做螺旋式读取 / 写入。
    • 举例:
      • 工业传感器阵列(如温度、压力传感器组成的二维网格),按螺旋顺序采集数据,确保 “先外围后核心” 的采样优先级;
      • 数据库中二维报表数据的导出 / 转换(比如将螺旋遍历的结果生成特定格式的报表)。
  • 面试价值:这是算法面试的经典题(LeetCode 54 题),掌握它能体现你对 “边界控制”“循环逻辑” 的理解,而这类边界处理能力是开发中处理复杂数据结构的基础(比如处理分页、多维数组分片)。
4. 硬件 / 嵌入式开发
  • 场景:对二维阵列硬件(如 LED 点阵屏、键盘矩阵)的驱动控制。
    • 举例:
      • LED 点阵屏实现螺旋式滚动显示文字 / 图案(比如从屏幕外围到中心逐步点亮像素);
      • 矩阵键盘的扫描策略(按螺旋顺序扫描按键,优化响应效率)。

二、实际应用示例(简化代码场景)

以 “LED 点阵屏螺旋点亮” 为例,核心逻辑复用螺旋遍历的边界控制思想:

// 模拟LED点阵屏(5x5),按螺旋顺序点亮像素(1=亮,0=灭) public class LedMatrix { public static void main(String[] args) { int[][] ledMatrix = new int[5][5]; // 初始全灭(0) spiralLight(ledMatrix); // 打印点亮后的点阵 for (int[] row : ledMatrix) { for (int pixel : row) { System.out.print(pixel + " "); } System.out.println(); } } // 螺旋点亮逻辑(复用原算法的边界控制) public static void spiralLight(int[][] matrix) { if (matrix == null || matrix.length == 0) return; int top = 0, bottom = matrix.length - 1; int left = 0, right = matrix[0].length - 1; int lightFlag = 1; // 标记是否点亮 while (top <= bottom && left <= right) { // 从左到右点亮上边界 for (int j = left; j <= right; j++) { matrix[top][j] = lightFlag; } top++; // 从上到下点亮右边界 for (int i = top; i <= bottom; i++) { matrix[i][right] = lightFlag; } right--; // 从右到左点亮下边界(判断是否有行) if (top <= bottom) { for (int j = right; j >= left; j--) { matrix[bottom][j] = lightFlag; } bottom--; } // 从下到上点亮左边界(判断是否有列) if (left <= right) { for (int i = bottom; i >= top; i--) { matrix[i][left] = lightFlag; } left++; } } } } 

输出效果(5x5 点阵全被螺旋式点亮为 1):

1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 

如果调整lightFlag为按遍历顺序递增(1、2、3...25),就能看到明显的螺旋数字排列,对应 LED 屏的螺旋显示效果。

总结

  1. 螺旋遍历矩阵的核心价值是按 “从外到内、顺时针” 的顺序处理二维结构数据,适配 “外围优先” 的业务逻辑;
  2. 实际应用集中在图形图像处理、数据可视化、硬件驱动等领域,同时也是算法能力的经典考察点;
  3. 其核心的 “边界收缩” 思想(top/bottom/left/right 控制)可迁移到各类二维数据的遍历场景(如分页处理、区域裁剪)。

Read more

MySQL:事务的理解

MySQL:事务的理解

一、CURD不加控制,会有什么问题  (1)因为,MySQL里面存的是数据,所以很有可能会被多个客户访问,所以mysqld可能一次会接受到多个关于CURD的请求。(2)且mysql内部是采用多线程来完成数据存储等相关工作的,所以必然会存在对数据并发访问的场景      ——>会导致一些多请求并发可能产生的异常结果        比如同行转账,按道理是我减100,你加100,但是因为我是同行所以用的是一张数据库的表,可能我减100的时候还没做完网络或者数据库出问题等其他原因导致没有给你加100,那么整个操作就会出现一个中间过程(我减了但是你没有加),这就有问题,在这种情况下我们允许异常产生,一旦操作没有完成我们应该把减掉的100再加回来,就好像什么都没做,等待下次合适的时候再去转账。这就相当于转账之后不要有中间过程,而是在转的时候一旦出现异常就直接进行回滚,因为不回滚的话就会有问题,必须得回滚保证和初始的状态一样,这就叫我们的回滚操作。在高并发的场景下数据或多或少都会出现这样的问题,所以这也就要求mysql必须要有针对这类问题的解决方案。 二、CURD满足什么属性,能解决上述

By Ne0inhk
华为OD机试双机位C卷:采购订单 (Py/Java/C/C++/Js/Go)

华为OD机试双机位C卷:采购订单 (Py/Java/C/C++/Js/Go)

采购订单 华为OD机试双机位C卷 - 华为OD上机考试双机位C卷 100分题型 华为OD机试双机位c卷真题目录点击查看: 华为OD机试双机位C卷真题题库目录|机考题库 + 算法考点详解 题目描述 在一个采购系统中,采购申请(PR)需要经过审批后才能生成采购订单(PO)。每个PR包含商品的单价(假设相同商品的单价一定是一样的)及数量信息。系统要求对商品进行分类处理:单价高于100元的商品需要单独处理,单价低于或等于100元的相同商品可以合并到同一采购订单PO中。针对单价低于100的小额订单,如果量大可以打折购买。 具体规则如下: 如果PR状态为"审批通过",则将其商品加入到PO中。如果PR的状态为"审批拒绝"或"待审批",则忽略改PR。 对于单价高于100元的商品,每个商品单独生成一条PO记录。对于单价低于100元的商品,将相同商品的数量合并到一条PO记录中。 如果商品单价<100且商品数量>=100,则单价打9折。 输入描述 第一行包含整数N,

By Ne0inhk
本文介绍如何利用Trae国际版的Agent Skill功能大幅提升Java后端开发效率,特别针对Spring Cloud微服务架构,包含完整的实战案例、代码示例和最佳实践。

本文介绍如何利用Trae国际版的Agent Skill功能大幅提升Java后端开发效率,特别针对Spring Cloud微服务架构,包含完整的实战案例、代码示例和最佳实践。

如何在Trae国际版中使用Agent Skill提升Java后端开发效率 引言 对于Java后端开发者,尤其是Spring Cloud微服务架构的使用者来说,日常工作中充满了重复的样板代码编写、繁琐的配置管理和复杂的调试工作。Trae国际版的Agent Skill功能就像是为Java开发者量身打造的"瑞士军刀",能够自动化这些重复劳动,让我们专注于更有创造性的架构设计和业务逻辑实现。 本文将结合Java后端开发的实际场景,特别是Spring Cloud微服务架构,详细介绍如何使用Trae国际版的Agent Skill大幅提升开发效率。 一、Trae国际版Agent Skill简介 1.1 什么是Agent Skill Agent Skill是Trae国际版中一种模块化的AI能力扩展机制,每个Skill都是一个专注于特定领域的"智能助手"。对于Java开发者来说,这些Skill可以理解为精通Java生态的"虚拟专家",能够处理从代码生成到架构设计的各种任务。 1.2 适合Java开发者的核心Skill * Spring Boot代码生成器:快速生成符合最佳实践的Sp

By Ne0inhk
【抽奖系统开发实战】Spring Boot 项目的用户模块设计:注册登录、权限管控与敏感数据加密

【抽奖系统开发实战】Spring Boot 项目的用户模块设计:注册登录、权限管控与敏感数据加密

文章目录 * 一、注册 * 1.1 敏感字段加密 * 1.2 用户注册 * 1.3 TypeHandler * 二、控制层通用异常处理 * 三、登录 * 3.1 发送验证码 * 3.2 Redis的配置与使用 * > 核心工具类`RedisUtil` * 3.3 JWT * > JWT 令牌介绍 * > 核心工具类`JWTUtil` * 3.4 管理员登录 * 四、强制登录 * 4.1 前端处理 * 4.2 后端处理 * 五、用户管理 * 5.1 后台管理页面

By Ne0inhk