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
题解
- 核心要点:解该题的关键在于维护四个边界变量,并在每遍历完一层后更新这些边界。通过这种方式,我们可以确保按照螺旋顺序遍历矩阵中的所有元素。
- 初始化边界:
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。 - 返回结果:
所有元素遍历完成后,返回结果列表。
- 初始化边界:
- 时间复杂度:O(mn)
- 空间复杂度:O(1)
- 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, 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]*/
- 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;
}
相关文章:
leetcode 面试经典 150 题:螺旋矩阵
链接螺旋矩阵题序号54题型二维数组(矩阵)解题方法模拟路径法难度中等熟练度✅✅✅ 题目 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 示例 1: 输入:matrix [[1,2,3…...
JAVA AOP简单实践(基于SpringBoot)
天行健,君子以自强不息;地势坤,君子以厚德载物。 每个人都有惰性,但不断学习是好好生活的根本,共勉! 文章均为学习整理笔记,分享记录为主,如有错误请指正,共同学习进步。…...
java agent的使用【通俗易懂版】
一、静态代理Agent 1.生成Agent的jar包 (1)创建Agent项目,引入javassist.jar包 (2)编写premain方法 import java.lang.instrument.Instrumentation;public class Agent1 {public static void premain(Stri…...
大模型学习指南
随着人工智能的迅猛发展,大模型成为了技术前沿的璀璨明星。踏入大模型学习领域,需要在多个关键方面下功夫。 扎实的数学功底是基石。线性代数为理解多维数据、矩阵运算提供支撑,像大模型中权重矩阵的处理就离不开它;概率论与数理…...
单片机:实现定时器中断(数码管读秒+LED闪烁)(附带源码)
单片机实现定时器中断:数码管读秒与LED闪烁 在单片机项目中,定时器中断是一个常见的应用,用于实现定时任务,例如定时更新显示或控制周期性事件。本文将介绍如何使用定时器中断实现数码管读秒和LED闪烁功能。通过使用定时器中断&a…...
STM32单片机芯片与内部33 ADC 单通道连续DMA
目录 一、ADC DMA配置——标准库 1、ADC配置 2、DMA配置 二、ADC DMA配置——HAL库 1、ADC配置 2、DMA配置 三、用户侧 1、DMA开关 (1)、标准库 (2)、HAL库 2、DMA乒乓 (1)、标准库 ÿ…...
【0376】Postgres内核 分配 last safe MultiXactId
上一篇: 【0375】Postgres内核 XLOG 之 设置下一个待分配 MultiXactId 和 offset 文章目录 1. 最后一个安全的 MultiXactId1.1 计算 multi wrap limit1.2 计算 multi stop limit1.3 计算 multi warn limit1.4 计算 multi vacuum limit2. 初始化 MultiXactState 成员3. 完成 mu…...
php时间strtotime函数引发的问题 时间判断出错
在 PHP 中,strtotime 函数能处理的最大时间范围取决于您的系统和 PHP 版本。 一般来说,它可以处理的时间范围从 1901 年 12 月 13 日到 2038 年 1 月 19 日。超过这个范围可能会导致不可预测的结果或错误。 如果您需要处理更大范围的时间,可能…...
Kibana:LINUX_X86_64 和 DEB_X86_64两种可选下载方式的区别
最近需要在vm(操作系统是 Ubuntu 22.04.4 LTS,代号 Jammy。这是一个基于 x86_64 架构的 Linux 发行版)上安装一个7.17.8版本的Kibana,并且不采用docker方式。 在下载的时候发现有以下两个选项,分别是 LINUX_X86_64 和 …...
【LeetCode每日一题】 LeetCode 151.反转字符串中的单词
LeetCode 151.反转字符串中的单词 题目描述 给你一个字符串 s ,请你反转字符串中单词的顺序。 单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。 返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。 注意:…...
gitlab克隆仓库报错fatal: unable to access ‘仓库地址xxxxxxxx‘
首次克隆仓库,失效了,上网查方法,都说是网络代理的问题,各种清理网络代理后都无效,去问同事: 先前都是直接复制的网页url当做远端url,或者点击按钮‘使用http克隆’ 这次对于我来说有效的远端u…...
在已有vue cli项目中添加单元测试配置
使用的是vue cli ^4.0.0的脚手架,项目采用的vue2进行编写,项目本身是没有使用单元测试的。应该挺多项目还是使用的vue2的项目进行开发的,自己在开发中过程中,还是发生了挺多需要记录原来功能的情况,这个时候去翻文档明…...
企业级NoSql数据库REDIS集群
1.1数据库主要分为两大类:关系型数据库与 NoSQL数据库 关系型数据库,是建立在关系模型基础上的数把库,其借助于集合代数等数学概念和方法来处理数据库中的数掘主流的 MySQLOracle、Ms sOLSerer和 DB2 都属于这类传统数据库 NoSQL数据库,全称…...
HTML与数据抓取:GET与POST方法详解
讲GET和POST就不能只讲GET和POST 你要讲HTTP请求的基本概念: HTTP(HyperText Transfer Protocol,超文本传输协议)是互联网上应用最为广泛的一种网络协议,主要用于Web浏览器与Web服务器之间的数据通信。HTTP是一个基于…...
【es6复习笔记】模板字符串(3)
介绍 模板字符串是 ES6 引入的一种新的字符串声明方式,它使用反引号()来定义字符串,而不是单引号()或双引号(")。模板字符串可以包含变量、表达式和换行符,这使得它…...
cursor保存更改操作技巧
1. 当我们在agent模式时,要求cursor更改代码时,cursor回答后,就已经更改了代码了,这时候就可以对程序进行编译和测试, 不一定先要点” accept“, 先测试如果没有问题再点“accept”,这样composer就会多一条…...
ASP.NET |日常开发中定时任务详解
ASP.NET |日常开发中定时任务详解 前言一、定时任务的概念与用途1.1 定义1.2 应用场景 二、在ASP.NET中实现定时任务的方式2.1 使用System.Timers.Timer2.2 使用Quartz.NET 三、定时任务的部署与管理3.1 部署考虑因素3.2 管理与监控 结束语优质源码分享 ASP.NET &am…...
【零基础保姆级教程】制作自己的数据集(二)——Labelme的安装与使用及常见的报错解决方法
前段时间安装了Labelimg,网上有些博客写着Labelme能进行语义分割的标注,但UI窗口就那么大找不着选项,只能打矩形框,为了能够标注自己的分割数据集,遂写下该教程以供参考。 采用Labelimg进行目标检测标注的教程如下。 …...
Move AI技术浅析(二):输入与预处理
一、视频输入模块 1.1 视频输入步骤详解 视频输入模块的主要任务是接收视频数据,并将其转换为后续处理所需的格式。具体步骤: 1.1.1 视频读取 步骤:从文件系统、网络流或摄像头读取视频数据。技术:使用 OpenCV 的 cv2.VideoCa…...
实践KDTS-WEB从mysql迁移到kingbasev9
数据库国产化替代数据迁移是一个复杂且关键的过程。这涉及到将原有数据库中的数据准确、完整地迁移到新的国产数据库中,同时确保数据的完整性和一致性。人大金仓提供了强大的数据库迁移工具(KDTS)对同构、异构数据库数据迁移; 数…...
跨设备进度同步:多设备追番中断的智能解决方案——Kazumi无缝续播体验
跨设备进度同步:多设备追番中断的智能解决方案——Kazumi无缝续播体验 【免费下载链接】Kazumi 基于自定义规则的番剧采集APP,支持流媒体在线观看,支持弹幕,支持实时超分辨率。 项目地址: https://gitcode.com/gh_mirrors/ka/Ka…...
langchain初步认识
LangChain提供了一系列方便的工具、组件和接口,大大降低了 AI 应用开发的门槛,也极大简化了大模型应用程序的开发过程。为什么需要 LangchainLangChain 尝试解决的问题:prompt的结构如何标准化如果我想中途随时切换大模型,怎样…...
Carsim与Simulink联合仿真模型——AEB的cpar文件、simulink模型文件及...
Carsim与Simulink联合仿真模型——AEB 提供cpar文件,simulink模型文件,模型搭建过程文档在汽车开发领域,安全系统始终占据着举足轻重的地位。其中,主动安全辅助系统(AEB)作为现代汽车的安全核心,…...
黑苹果EFI配置革命:3大痛点与OpCore Simplify的智能解决方案
黑苹果EFI配置革命:3大痛点与OpCore Simplify的智能解决方案 【免费下载链接】OpCore-Simplify A tool designed to simplify the creation of OpenCore EFI 项目地址: https://gitcode.com/GitHub_Trending/op/OpCore-Simplify 开篇直击:黑苹果配…...
FanControl中文界面解决方案:从问题诊断到高效应用的实战指南
FanControl中文界面解决方案:从问题诊断到高效应用的实战指南 【免费下载链接】FanControl.Releases This is the release repository for Fan Control, a highly customizable fan controlling software for Windows. 项目地址: https://gitcode.com/GitHub_Tren…...
如何永久保存番茄小说?3个强力方案告别网络依赖
如何永久保存番茄小说?3个强力方案告别网络依赖 【免费下载链接】fanqienovel-downloader 下载番茄小说 项目地址: https://gitcode.com/gh_mirrors/fa/fanqienovel-downloader 你是否曾在深夜追更时突然断网?是否担心喜欢的小说某天会从平台消失…...
Oracle 26ai新特性:时区、表空间、审计方面的新特性
Oracle 26ai新特性:时区、表空间、审计方面的新特性 1. SYSDATE 和 SYSTIMESTAMP 支持 PDB 级时区 变更内容:SYSDATE 和 SYSTIMESTAMP 现在可以按每个 PDB(可插拔数据库)单独设置时区,而不是继承操作系统时区。 -- 26a…...
OpenClaw版本升级指南:Qwen3-14b_int4_awq兼容性检查清单
OpenClaw版本升级指南:Qwen3-14b_int4_awq兼容性检查清单 1. 为什么需要这份升级指南 上周五晚上11点,我的OpenClaw突然罢工了——当时它正在帮我自动整理会议纪要,突然弹出一条错误提示:"Model provider configuration in…...
docker-2025-tech-blog
Docker 零基础入门:2026 年还值不值得学?一篇讲清镜像、容器与 Compose DockerDocker 零基础入门:2026 年还值不值得学?一篇讲清镜像、容器与 Compose前言一、Docker 到底能解决什么问题?二、什么是 Docker?…...
RAG 回答总“差点意思“?小白程序员必备:附代码实战两把索引优化钥匙(收藏版)
本文针对 RAG 搭建后回答质量不高的问题,介绍了两种优化方法:句子窗口检索和结构化递归检索。句子窗口检索通过聚焦最小句子并扩展为完整段落来提升答案质量;结构化递归检索则通过元数据标签先过滤再搜索,特别适合大规模知识库。文…...

