【LeetCode Hot100】螺旋矩阵|边界模拟,Java实现,图解+代码

💻 [LeetCode Hot100] 螺旋矩阵|边界模拟,Java实现!图解+代码

✏️本文对应题目链接:螺旋矩阵


📌 题目描述

给你一个 mn 列的矩阵 matrix,请按照 顺时针螺旋顺序,返回矩阵中的所有元素。

示例:

输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
输出:[1,2,3,6,9,8,7,4,5]
解释:顺时针螺旋顺序遍历矩阵。

🧠 解题思路(图文分解)

❗ 核心难点

如何模拟顺时针螺旋遍历矩阵的边界?


方法一:边界模拟法(黄金思路)✨

关键步骤:

  1. 定义边界
    • leftrighttopbottom 分别表示当前遍历的左右上下边界
  2. 模拟遍历
    • 从左到右遍历上边界
    • 从上到下遍历右边界
    • 从右到左遍历下边界
    • 从下到上遍历左边界
  3. 更新边界:每次遍历完一个边界后,缩小边界范围
  4. 终止条件:当边界范围无效时停止遍历

图解边界模拟

输入矩阵:

matrix = [
  [1, 2, 3],
  [4, 5, 6],
  [7, 8, 9]
]

步骤1:初始化边界

left = 0, right = 2
top = 0, bottom = 2

步骤2:模拟遍历

- 从左到右遍历上边界 → [1,2,3]
- 从上到下遍历右边界 → [6,9]
- 从右到左遍历下边界 → [8,7]
- 从下到上遍历左边界 → [4]

步骤3:更新边界

left = 1, right = 1
top = 1, bottom = 1

步骤4:继续遍历

- 从左到右遍历上边界 → [5]

最终结果:

[1,2,3,6,9,8,7,4,5]

🚀 代码实现

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

💡 复杂度分析

  • 时间复杂度:O(m * n) → 遍历矩阵中的每个元素一次
  • 空间复杂度:O(1) → 仅用常数空间(结果列表不计入空间复杂度)

方法二:方向模拟法(进阶思路)

关键思路:使用方向数组模拟螺旋遍历,适合复杂路径问题。

class Solution {
    public List<Integer> spiralOrder(int[][] matrix) {
        List<Integer> result = new ArrayList<>();
        if (matrix == null || matrix.length == 0) {
            return result;
        }
        
        int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; // 右、下、左、上
        int m = matrix.length, n = matrix[0].length;
        boolean[][] visited = new boolean[m][n];
        int directionIndex = 0;
        int row = 0, col = 0;
        
        for (int i = 0; i < m * n; i++) {
            result.add(matrix[row][col]);
            visited[row][col] = true;
            int nextRow = row + directions[directionIndex][0];
            int nextCol = col + directions[directionIndex][1];
            if (nextRow < 0 || nextRow >= m || nextCol < 0 || nextCol >= n || visited[nextRow][nextCol]) {
                directionIndex = (directionIndex + 1) % 4; // 改变方向
            }
            row += directions[directionIndex][0];
            col += directions[directionIndex][1];
        }
        
        return result;
    }
}

🌟 总结要点

边界模拟核心思想:通过缩小边界模拟螺旋遍历
方向模拟法核心:利用方向数组处理复杂路径问题
适用场景:矩阵遍历、路径模拟


<think>我们正在处理的是LeetCode54题:螺旋矩阵。给定一个mxn的矩阵,按照螺旋顺序返回矩阵中的所有元素。根据引用内容,我们可以采用模拟螺旋路径的方法,使用方向数组来控制移动方向,当遇到边界或已访问的元素时改变方向。算法步骤:1.定义方向数组DIRS,表示右、下、左、上四个方向(顺时针)。2.初始化一个与输入矩阵同样大小的visited矩阵(或者修改原矩阵标记已访问)?但引用[1]中使用了将访问过的位置标记为Integer.MAX_VALUE的方法,这样可以在原矩阵上操作,避免额外空间。但注意题目要求不能修改原矩阵?题目没有明确,但通常我们应避免修改原数据。不过引用[1]的方法修改了原矩阵,如果要求不修改,则需要额外空间。3.另一种方法是使用边界收缩法(引用[3]提到),但引用[1]的方法更简洁。然而,题目要求返回列表,不要求保留原矩阵,所以我们可以修改原矩阵(但题目没有说可以修改,所以最好不修改?)。但引用[1]的解法修改了原矩阵。我们也可以使用一个visited数组来记录访问过的位置,这样就不修改原矩阵。考虑到题目矩阵大小不超过10x10,使用额外空间是可以接受的。但引用[1]的方法已经比较高效,且代码简洁。这里我们采用引用[1]的方法,但注意题目中矩阵元素可能包含负数,所以标记值不能是Integer.MIN_VALUE?因为题目中元素范围在-100100,所以我们可以使用一个超出这个范围的值(比如101或Integer.MAX_VALUE)作为标记。但是,题目没有说不能修改原矩阵,所以我们可以使用。但是,如果我们不想修改原矩阵,我们可以使用一个同样大小的boolean数组来记录访问情况。两种方法都可以,这里我们提供两种实现,但根据引用[1],我们先给出修改原矩阵实现(因为代码简洁),然后再提供一个不修改原矩阵实现(使用边界收缩法)。不过,引用[3]提到边界收缩法,我们也可以实现。由于问题要求包含输入输出示例,我们将提供:1.算法实现(两种方法)2.输入输出示例方法一:模拟路径(修改原矩阵)-使用方向数组,按顺序向右、向下、向左、向上移动。-当下一步到达矩阵边界或已经访问过的位置时,改变方向(通过取余循环切换方向)。-使用一个变量记录当前方向,每次移动后判断下一步是否需要转向。方法二:边界收缩法(不修改原矩阵)-定义四个边界:上边界top=0,下边界bottom=m-1,左边界left=0,右边界right=n-1。-按照顺时针方向遍历:1.从左到右遍历上边界(top行),遍历完上边界下移(top++)2.从上到下遍历右边界(right列),遍历完右边界左移(right--)3.从右到左遍历下边界(bottom行),遍历完下边界上移(bottom--)4.从下到上遍历左边界(left列),遍历完左边界右移(left++)-循环条件:top<=bottom且left<=right方法二更直观,且不需要修改原矩阵,也不需要额外的标记数组,空间复杂度O(1)(除了输出列表)。我们选择方法二作为主要实现,因为它更符合题目要求(不修改原矩阵)且高效。下面给出Java实现:方法二:边界收缩法步骤:初始化top=0,bottom=m-1,left=0,right=n-1。初始化结果列表ans。while(top<=bottom&&left<=right){1.从左到右:遍历top行的left到right列,将元素加入ans。然后top++。2.从上到下:遍历right列的top到bottom行,将元素加入ans。然后right--。3.检查是否还有行(因为top可能已经超过bottom):从右到左:遍历bottom行的right到left列(逆序),将元素加入ans。然后bottom--。4.检查是否还有列:从下到上:遍历left列的bottom到top行(逆序),将元素加入ans。然后left++。}注意:在第3步和第4步之前,需要检查是否还有行/列,因为可能已经遍历完了(比如只有一行或一列的情况)。具体代码:输入输出示例:输入:matrix=[[1,2,3,4],[5,6,7,8],[9,10,11,12]]输出:[1,2,3,4,8,12,11,10,9,5,6,7]代码实现:</think>### LeetCode 54:螺旋矩阵 Java 实现 #### 问题描述 给定一个 m×n 的矩阵,按照顺时针螺旋顺序返回矩阵中的所有元素。 **示例输入**: ```java int[][] matrix = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 10, 11, 12} }; ``` **示例输出**: ``` [1,2,3,4,8,12,11,10,9,5,6,7] ``` --- ### 高效实现方案(边界收缩法) ```java import java.util.ArrayList; import java.util.List; class Solution { public List<Integer> spiralOrder(int[][] matrix) { List<Integer> result = new ArrayList<>(); if (matrix == null || matrix.length == 0) return result; int top = 0, bottom = matrix.length - 1; int left = 0, right = matrix[0].length - 1; while (top <= bottom && left <= right) { // 1. 从左到右遍历顶层 for (int j = left; j <= right; j++) { result.add(matrix[top][j]); } top++; // 2. 从上到下遍历右侧 for (int i = top; i <= bottom; i++) { result.add(matrix[i][right]); } right--; // 3. 检查是否仍有行需要处理 if (top <= bottom) { // 从右到左遍历底层 for (int j = right; j >= left; j--) { result.add(matrix[bottom][j]); } bottom--; } // 4. 检查是否仍有列需要处理 if (left <= right) { // 从下到上遍历左侧 for (int i = bottom; i >= top; i--) { result.add(matrix[i][left]); } left++; } } return result; } } ``` --- ### 算法解析 1. **边界初始化**: - `top=0`, `bottom=行数-1` - `left=0`, `right=列数-1` 2. **四步循环**: ```java while (top <= bottom && left <= right) { // 向右遍历 → [top行, left→right] // 向下遍历 ↓ [right列, top→bottom] // 向左遍历 ← [bottom行, right→left] (需检查top<=bottom) // 向上遍历 ↑ [left列, bottom→top] (需检查left<=right) } ``` 3. **边界收缩**: - 每完成一个方向遍历后收缩对应边界 - 例如:完成顶层遍历后 `top++` 4. **条件检查**: - 向左/向上遍历前需检查边界有效性 - 防止单行/单列情况下的重复遍历[^1] --- ### 时间复杂度分析 - **时间复杂度**:$O(m \times n)$ 需访问矩阵中的每个元素恰好一次 - **空间复杂度**:$O(1)$(不考虑输出列表) 仅使用固定数量的指针变量 --- ### 测试用例 ```java public static void main(String[] args) { Solution solution = new Solution(); // 示例测试 int[][] matrix1 = {{1,2,3},{4,5,6},{7,8,9}}; System.out.println(solution.spiralOrder(matrix1)); // 输出: [1,2,3,6,9,8,7,4,5] int[][] matrix2 = {{1,2,3,4},{5,6,7,8},{9,10,11,12}}; System.out.println(solution.spiralOrder(matrix2)); // 输出: [1,2,3,4,8,12,11,10,9,5,6,7] // 边界测试 int[][] matrix3 = {{7}}; System.out.println(solution.spiralOrder(matrix3)); // 输出: [7] } ``` --- ### 应用场景 1. **图像处理**:像素矩阵螺旋遍历 2. **游戏开发**:地图探索路径规划 3. **数据压缩**:矩阵数据的螺旋编码 4. **内存管理**:二维存储结构的访问优化[^3] --- ### 相关问题 1. 如何实现**逆时针**螺旋遍历矩阵? 2. 如何处理**非矩形**(如三角形)矩阵螺旋遍历? 3. 如何将螺旋遍历算法扩展**三维矩阵**? 4. 在图像处理中,螺旋遍历如何优化**局部性原理**? 5. 如何修改算法实现**从外向内**和**从内向外**两种螺旋顺序?[^2]
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值