leetcode 面试经典 150 题:螺旋矩阵

链接螺旋矩阵
题序号54
题型二维数组(矩阵)
解题方法模拟路径法
难度中等
熟练度✅✅✅

题目

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

  • 示例 1:
    输入:matrix = [[1,2,3],[4,5,6],[7,8,9]]
    输出:[1,2,3,6,9,8,7,4,5]
    在这里插入图片描述

  • 示例 2:
    输入: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]
    在这里插入图片描述

  • 提示:
    m == matrix.length
    n == matrix[i].length
    1 <= m, n <= 10
    -100 <= matrix[i][j] <= 100

题解

  1. 核心要点:解该题的关键在于维护四个边界变量,并在每遍历完一层后更新这些边界。通过这种方式,我们可以确保按照螺旋顺序遍历矩阵中的所有元素。
    • 初始化边界
      top 和 bottom 分别初始化为矩阵的第一行和最后一行的索引。
      left 和 right 分别初始化为矩阵的第一列和最后一列的索引。
    • 循环条件
      当 top 小于等于 bottom 且 left 小于等于 right 时,继续循环。这个条件确保了我们不会在矩阵遍历完成后继续执行。
    • 遍历顶部行
      从 left 到 right 遍历 top 行,将元素添加到结果列表中。
      遍历完成后,将 top 索引加1,因为顶部行已经遍历完成。
    • 遍历右侧列
      从 top 到 bottom 遍历 right 列,将元素添加到结果列表中。
      遍历完成后,将 right 索引减1,因为右侧列已经遍历完成。
    • 检查是否需要继续遍历
      如果 top 小于等于 bottom,则说明还有底部行需要遍历。
      从 right 到 left 遍历 bottom 行,将元素添加到结果列表中。
      遍历完成后,将 bottom 索引减1。
    • 遍历左侧列
      如果 left 小于等于 right,则说明还有左侧列需要遍历。
      从 bottom 到 top 遍历 left 列,将元素添加到结果列表中。
      遍历完成后,将 left 索引加1。
    • 返回结果
      所有元素遍历完成后,返回结果列表。
  2. 时间复杂度:O(mn)
  3. 空间复杂度:O(1)
  4. c++ 实现算法
class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> result;
        
        if (matrix.empty()) return result;
        
        int top = 0, bottom = matrix.size() - 1;
        int left = 0, right = matrix[0].size() - 1;
        
        while (top <= bottom && left <= right) {
            // 从左到右沿着最上面一行遍历
            for (int i = left; i <= right; ++i) {
                result.push_back(matrix[top][i]);
            }
            top++;  // 将顶部边界向下移动
            
            // 从上到下沿着最右列遍历。
            for (int i = top; i <= bottom; ++i) {
                result.push_back(matrix[i][right]);
            }
            right--;  //将右边界向左移动
            
            if (top <= bottom) {
                //从右向左沿着底部一行遍历
                for (int i = right; i >= left; --i) {
                    result.push_back(matrix[bottom][i]);
                }
                bottom--;  //将底部边界向上移动
            }
            
            if (left <= right) {
                //从底向上沿着最左列遍历
                for (int i = bottom; i >= top; --i) {
                    result.push_back(matrix[i][left]);
                }
                left++;  //将左边界向右移动
            }
        }
        
        return result;
    }
};
  1. 演示
/*
假设输入矩阵为:

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

初始状态:
top = 0, bottom = 2, left = 0, right = 2
result = [](最终结果)

第一步:从左到右遍历上边界
我们首先遍历矩阵的上边界,从左到右:
遍历 matrix[0][0] = 1, matrix[0][1] = 2, matrix[0][2] = 3,把它们添加到 result 中。
更新 result:[1, 2, 3]
增加 top,使 top = 1。
当前状态:
result = [1, 2, 3]
top = 1, bottom = 2, left = 0, right = 2

第二步:从上到下遍历右边界
接下来遍历右边界,从上到下:
遍历 matrix[1][2] = 6,matrix[2][2] = 9,把它们添加到 result 中。
更新 result:[1, 2, 3, 6, 9]
减少 right,使 right = 1。
当前状态:
result = [1, 2, 3, 6, 9]
top = 1, bottom = 2, left = 0, right = 1

第三步:从右到左遍历下边界
接下来遍历下边界,从右到左:
遍历 matrix[2][1] = 8, matrix[2][0] = 7,把它们添加到 result 中。
更新 result:[1, 2, 3, 6, 9, 8, 7]
减少 bottom,使 bottom = 1。
当前状态:
result = [1, 2, 3, 6, 9, 8, 7]
top = 1, bottom = 1, left = 0, right = 1

第四步:从下到上遍历左边界
接下来遍历左边界,从下到上:
遍历 matrix[1][0] = 4,把它添加到 result 中。
更新 result:[1, 2, 3, 6, 9, 8, 7, 4]
增加 left,使 left = 1。
当前状态:
result = [1, 2, 3, 6, 9, 8, 7, 4]
top = 1, bottom = 1, left = 1, right = 1

第五步:从左到右遍历上边界(再次)
接下来遍历上边界,从左到右(当前上边界就是 matrix[1][1]):
遍历 matrix[1][1] = 5,把它添加到 result 中。
更新 result:[1, 2, 3, 6, 9, 8, 7, 4, 5]
增加 top,使 top = 2。
当前状态:
result = [1, 2, 3, 6, 9, 8, 7, 4, 5]
top = 2, bottom = 1, left = 1, right = 1

终止条件
此时 top > bottom,left > right,我们退出循环。
最终结果为:
[1, 2, 3, 6, 9, 8, 7, 4, 5]
 */
  1. c++ 完整demo
#include <vector>
#include <iostream>
using namespace std;

class Solution {
public:
    vector<int> spiralOrder(vector<vector<int>>& matrix) {
        vector<int> result;
        
        if (matrix.empty()) return result;
        
        int top = 0, bottom = matrix.size() - 1;
        int left = 0, right = matrix[0].size() - 1;
        
        while (top <= bottom && left <= right) {
            // 从左到右沿着最上面一行遍历
            for (int i = left; i <= right; ++i) {
                result.push_back(matrix[top][i]);
            }
            top++;  // 将顶部边界向下移动
            
            // 从上到下沿着最右列遍历。
            for (int i = top; i <= bottom; ++i) {
                result.push_back(matrix[i][right]);
            }
            right--;  //将右边界向左移动
            
            if (top <= bottom) {
                //从右向左沿着底部一行遍历
                for (int i = right; i >= left; --i) {
                    result.push_back(matrix[bottom][i]);
                }
                bottom--;  //将底部边界向上移动
            }
            
            if (left <= right) {
                //从底向上沿着最左列遍历
                for (int i = bottom; i >= top; --i) {
                    result.push_back(matrix[i][left]);
                }
                left++;  //将左边界向右移动
            }
        }
        
        return result;
    }
};

int main() {
    Solution solution;
    vector<vector<int>> matrix = {
        { 1, 2, 3 },
        { 4, 5, 6 },
        { 7, 8, 9 }
    };
    
    vector<int> result = solution.spiralOrder(matrix);
    
    // 输出结果
    for (int num : result) {
        cout << num << " ";
    }
    cout << endl;
    
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/944122.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

汽车CAN通信逻辑与LabVIEW开发

CAN通信的核心概念 CAN&#xff08;Controller Area Network&#xff09;是一种多主通信协议&#xff0c;广泛应用于汽车电子系统中&#xff0c;用于控制单元之间的高效通信。 ​ 消息优先级&#xff1a;每个CAN帧包含唯一的标识符&#xff08;ID&#xff09;&#xff0c;ID的…

CI/CD是什么?

CI/CD 定义 CI/CD 代表持续集成和持续部署&#xff08;或持续交付&#xff09;。它是一套实践和工具&#xff0c;旨在通过自动化构建、测试和部署来改进软件开发流程&#xff0c;使您能够更快、更可靠地交付代码更改。 持续集成 (CI)&#xff1a;在共享存储库中自动构建、测试…

Kubernetes之NodeSelector与NodeName实战

目录 目标 版本 官网 概述 实战 NodeName实战 NodeSelector实战 目标 通过配置NodeSelector与NodeName实现Pod运行&#xff08;或优先运行&#xff09;在我们期望的节点之上。了解这两种实现方法的区别。 版本 Kubernets v1.25.0 官网 将Pod分配给节点https://kubernet…

如何构建有效的AI Agents:从复杂到简约——深度解读Claude实践总结《Building effective agents》(上)

在人工智能技术日新月异的今天&#xff0c;大语言模型(LLM)已经成为技术创新的热点。 然而&#xff0c;在追逐技术前沿的热潮中&#xff0c;我们是否忽视了工程设计的本质&#xff1f; 作为全球人工智能领域的领军企业之一&#xff0c;Anthropic以其在AI安全和伦理方面的深入…

高中数学刷题版:函数奇偶性[干货]

文章目录 一、奇偶性定义例题 二、运算性质1、两个函数的和差积商2、复合函数3、画草图4、对称中心与对称轴 三、奇偶性判断例题 四、根据奇偶性求解析式例题 五、单调性与奇偶性的综合应用例题 一、奇偶性定义 1、定义域都是关于原点对称。 2、解析式关系 奇函数&#xff1a;…

【Sentinel】流控效果与热点参数限流

目录 1.流控效果 1.1.warm up 2.2.排队等待 1.3.总结 2.热点参数限流 2.1.全局参数限流 2.2.热点参数限流 2.3.案例 1.流控效果 在流控的高级选项中&#xff0c;还有一个流控效果选项&#xff1a; 流控效果是指请求达到流控阈值时应该采取的措施&#xff0c;包括三种&…

【Rust自学】7.4. use关键字 Pt.2 :重导入与换国内镜像源教程

喜欢的话别忘了点赞、收藏加关注哦&#xff0c;对接下来的教程有兴趣的可以关注专栏。谢谢喵&#xff01;(&#xff65;ω&#xff65;) 7.4.1. 使用pub use重新导入名称 使用use将路径导入作用域内后。该名称在词作用域内是私有的。 以上一篇文章的代码为例&#xff1a; m…

集装箱的纸箱和塑料箱识别数据集,使用YOLO,COCO JSON,PASICAL VOC XML格式标注,识别准确率高达97.5%

集装箱的纸箱和塑料箱识别数据集&#xff0c;使用YOLO&#xff0c;COCO JSON&#xff0c;PASICAL VOC XML格式标注&#xff0c;识别准确率高达97.5% 数据集分割 训练组88&#xff05; 4605图片 有效集8% 438图片 测试集4% 219图片 预处理 自动定向&#x…

TOP K问题:利用堆排序找出数组中最小的k个数

设计一个算法&#xff0c;找出数组中最小的k个数。以任意顺序返回这k个数均可。 找小的数需要建大堆来解决&#xff0c;首先将数组中前K个数建成一个大堆&#xff0c;将从k1个数直到数组结束的所有数与堆顶的数进行比较&#xff0c;如果比堆顶的数小&#xff0c;则替换堆顶的数…

VDA 学习手册

VDA&#xff08;Verband der Automobilindustrie&#xff0c;德国汽车工业联合会&#xff09;报文标准是专为汽车行业制定的电子数据交换&#xff08;EDI&#xff09;标准&#xff0c;用于支持供应链管理中的数据传输。它是由德国汽车工业联合会开发和维护的&#xff0c;广泛应…

自动化测试- 自动化测试模型

目录 自动化测试模型简介 1、线性模型 举例 测试页面html文件 测试脚本 2. 关键字驱动测试&#xff08;Keyword-Driven Testing&#xff09; 需测试内容 关键字驱动测试框架 创建测试用例文件 运行测试 3. 数据驱动测试&#xff08;Data-Driven Testing&#xff09; …

【Halcon】例程讲解:基于形状匹配与OCR的多图像处理(附图像、程序下载链接)

1. 开发需求 在参考图像中定义感兴趣区域&#xff08;ROI&#xff09;&#xff0c;用于形状匹配和文本识别。通过形状匹配找到图像中的目标对象位置。对齐多幅输入图像&#xff0c;使其与参考图像保持一致。在对齐后的图像上进行OCR识别&#xff0c;提取文本和数字信息。以循环…

快速理解24种设计模式

简单工厂模式 建立产品接口类&#xff0c;规定好要实现方法。 建立工厂类&#xff0c;根据传入的参数&#xff0c;实例化所需的类&#xff0c;实例化的类必须实现指定的产品类接口 创建型 单例模式Singleton 保证一个类只有一个实例&#xff0c;并提供一个访问他它的全局…

CKA认证 | Day7 K8s存储

第七章 Kubernetes存储 1、数据卷与数据持久卷 为什么需要数据卷&#xff1f; 容器中的文件在磁盘上是临时存放的&#xff0c;这给容器中运行比较重要的应用程序带来一些问题。 问题1&#xff1a;当容器升级或者崩溃时&#xff0c;kubelet会重建容器&#xff0c;容器内文件会…

【JavaEE进阶】@RequestMapping注解

目录 &#x1f4d5;前言 &#x1f334;项目准备 &#x1f332;建立连接 &#x1f6a9;RequestMapping注解 &#x1f6a9;RequestMapping 注解介绍 &#x1f384;RequestMapping是GET还是POST请求&#xff1f; &#x1f6a9;通过Fiddler查看 &#x1f6a9;Postman查看 …

ROUGE指标在自然语言处理中的应用:从理论到实践

引言 你是否曾经遇到过机器生成的文本摘要与原文内容不符的情况&#xff1f;或者在使用机器翻译时&#xff0c;发现译文虽然“看起来”正确&#xff0c;但语义却与原文相差甚远&#xff1f;在自然语言处理&#xff08;NLP&#xff09;领域&#xff0c;如何科学地评估生成文本的…

编译openssl遇到错误Parse errors: No plan found in TAP output的解决方法

在编译openssl时 tar -zxvf openssl-1.1.1p.tar.gz cd openssl-1.1.1p ./config --prefix/usr --openssldir/etc/ssl --shared zlib make make test 遇到错误 Parse errors: No plan found in TAP output 解决方法&#xff1a; yum install perl-Test-Simple

Visual Studio 2017 配置 OpenCV 4.5.5 及二次配置的导入

重点参考&#xff1a; Visual Studio 2017 OpenCV_4.5.0安装_opencv4.5.0下载-CSDN博客 VS2017配置OpenCV4.5_vs2017 opencv4.5.4-CSDN博客 下载准备工作就不说了&#xff0c;直接从官网下载就行了。 关键就两步&#xff1a; 1&#xff09;将OpenCV的bin目录添加到环境变量…

42 模板进阶

目录 一、非类型形参 &#xff08;一&#xff09;简介 &#xff08;二&#xff09;非类型形参与宏的区别 &#xff08;三&#xff09;注意点 二、模板的特化 &#xff08;一&#xff09;概念 &#xff08;二&#xff09;函数模板的特化 &#xff08;三&#xff…

接口测试面试题

接口测试在软件测试中占据重要位置&#xff0c;无论是功能测试还是性能测试&#xff0c;接口的稳定性至关重要。以下总结了一些常见的接口测试面试题&#xff0c;帮助你从容应对面试挑战&#xff01; 面试官常说&#xff1a;“接口测试是测试的重头戏&#xff0c;了解接口的设计…