【LeetCode】 54. Spiral Matrix

本文介绍两种螺旋矩阵遍历算法,一种使用visited数组记录遍历状态,另一种按圈层逐层遍历。第一种算法通过定义方向数组实现顺时针遍历,第二种算法将矩阵视为多个圈层,从外向内遍历每一圈。两种算法均适用于M×N矩阵的顺时针遍历。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

54. Spiral Matrix

题目描述

给定M×N个元素的矩阵(M行,N列),以顺时针的方向返回矩阵的所有元素。
在这里插入图片描述

解题思路1

我一开始思路和我的上一篇498- Diagonal Traverse有些相似之处,都是按照一定的方式遍历一个矩阵,不同的是这道题需要判断下一坐标是否遍历过,通过定义一个visited数组就可以实现。

参考代码1
class Solution {
    private int n;
    private int m;
    private int[][] visited; // 判断坐标是否遍历过

    public List<Integer> spiralOrder(int[][] matrix) {
        if(matrix.length == 0)
            return null;
        List<Integer> result = new ArrayList<>();
        n = matrix.length;
        m = matrix[0].length;
        visited = new int[n][m]; // 数组初始化值全为0

        int nextX, nextY;
        int x = 0, y = 0;

        // 顺时针四个方向,→ ↓ ← ↑,当前方向
        int[] go = {1, 2, 3, 4};
        int now = 0;

        do {
            result.add(matrix[x][y]);
            visited[x][y] = 1;
            // 方向 →
            if (go[now] == 1) {
                nextY = y + 1;
                if (inArea(x, nextY) && !isVisited(x, nextY)) {
                    y++;
                } else {
                    // 改变方向
                    now = ++now % 4;
                    x++;
                }
            } else if (go[now] == 2) {
                nextX = x + 1;
                if (inArea(nextX, y) && !isVisited(nextX, y)) {
                    x++;
                } else {
                    now = ++now % 4;
                    y--;
                }
            } else if (go[now] == 3) {
                nextY = y - 1;
                if (inArea(x, nextY) && !isVisited(x, nextY)) {
                    y--;
                } else {
                    now = ++now % 4;
                    x--;
                }
            } else if (go[now] == 4) {
                nextX = x - 1;
                if (inArea(nextX, y) && !isVisited(nextX, y)) {
                    x--;
                } else {
                    now = ++now % 4;
                    y++;
                }
            }
        } while (result.size() != n * m);
        return result;
    }

    // 判断坐标是否在数组内
    boolean inArea(int x, int y) {
        return x >= 0 && x < n && y >= 0 && y < m;
    }

    // 判断下一坐标是否已经遍历过
    boolean isVisited(int x, int y) {
        return visited[x][y] == 1;
    }
}
解题思路2(剑指Offer 29

今天看剑指offer就刚好遇到了这题。。。

解决这道题的关键在于先形成清晰的思路,并把复杂的问题分解成若干个简单的问题。

  • 把矩阵想象成若干个圈,每次从外到内依次遍历一圈 , 每次遍历都是从行坐标和列坐标相等的坐标开始遍历(start, start)。
  • 结束条件 : result.size() > rows * columns ;

也可以根据行坐标、列坐标和行数、列数的关系来判断:如果行坐标 * 2 大于等于行数的话,那么当前坐标的下一列一定已经遍历过了,此时遍历结束,同理列坐标也一样,于是得到 columns > start * 2 && rows > start * 2

  • 每次遍历一圈需要四步,从左到右,从上到下,从右到左,从下到上,每一步可以根据起始坐标和终止坐标完成遍历;
  • 但是遍历最后一圈时,可能只需走三步,两步甚至一步。
  • 遍历每一步的前提条件 :第一步是必须的;第二步前提是终止行号大于起始行号;第三步前提是终止行号大于起始行号,终止列号大于起始列号;第三步前提是终止行号比起始行号大2,同时终止列号大于起始列号。
参考代码2
class Solution2 {
    public List<Integer> spiralOrder(int[][] matrix) {
        List<Integer> result = new ArrayList<>();
        if (matrix.length == 0) {
            return result;
        }

        int rows = matrix.length;
        int columns = matrix[0].length;
        int start = 0;

        // while (columns > start * 2 && rows > start * 2) { // 
        while (result.length <= rows * columns) {
            int endX = columns - 1 - start;
            int endY = rows - 1 - start;

            // 从左到右打印一行
            for (int i = start; i <= endX; i++) {
                result.add(matrix[start][i]);
            }

            // 从上到下打印一行
            if (start < endY) {
                for (int i = start + 1; i <= endY; ++i) {
                    result.add(matrix[i][endX]);
                }
            }

            // 从右到左打印一行
            if (start < endX && start < endY) {
                for (int i = endX - 1; i >= start; i--) {
                    result.add(matrix[endY][i]);
                }
            }

            // 从上到下打印一行
            if (start < endX && start < endY - 1) {
                for (int i = endY - 1; i >= start + 1; i--) {
                    result.add(matrix[i][start]);
                }
            }
            start++;
        }
        return result;
    }
}

内容概要:本文详细介绍了扫描单分子定位显微镜(scanSMLM)技术及其在三维超分辨体积成像中的应用。scanSMLM通过电调透镜(ETL)实现快速轴向扫描,结合4f检测系统将不同焦平面的荧光信号聚焦到固定成像面,从而实现快速、大视场的三维超分辨成像。文章不仅涵盖了系统硬件的设计与实现,还提供了详细的软件代码实现,包括ETL控制、3D样本模拟、体积扫描、单分子定位、3D重建和分子聚类分析等功能。此外,文章还比较了循环扫描与常规扫描模式,展示了前者在光漂白效应上的优势,并通过荧光珠校准、肌动蛋白丝、线粒体网络和流感A病毒血凝素(HA)蛋白聚类的三维成像实验,验证了系统的性能和应用潜力。最后,文章深入探讨了HA蛋白聚类与病毒感染的关系,模拟了24小时内HA聚类的动态变化,提供了从分子到细胞尺度的多尺度分析能力。 适合人群:具备生物学、物理学或工程学背景,对超分辨显微成像技术感兴趣的科研人员,尤其是从事细胞生物学、病毒学或光学成像研究的科学家和技术人员。 使用场景及目标:①理解和掌握scanSMLM技术的工作原理及其在三维超分辨成像中的应用;②学习如何通过Python代码实现完整的scanSMLM系统,包括硬件控制、图像采集、3D重建和数据分析;③应用于单分子水平研究细胞内结构和动态过程,如病毒入侵机制、蛋白质聚类等。 其他说明:本文提供的代码不仅实现了scanSMLM系统的完整工作流程,还涵盖了多种超分辨成像技术的模拟和比较,如STED、GSDIM等。此外,文章还强调了系统在硬件改动小、成像速度快等方面的优势,为研究人员提供了从理论到实践的全面指导。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值