【面试经典150 | 矩阵】螺旋矩阵

文章目录

  • 写在前面
  • Tag
  • 题目来源
  • 题目解读
  • 解题思路
    • 方法一:模拟
    • 方法二:按层模拟
  • 写在最后

写在前面

本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更……

专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行回顾与总结,文章结构大致如下,部分内容会有增删:

  • Tag:介绍本题牵涉到的知识点、数据结构;
  • 题目来源:贴上题目的链接,方便大家查找题目并完成练习;
  • 题目解读:复述题目(确保自己真的理解题目意思),并强调一些题目重点信息;
  • 解题思路:介绍一些解题思路,每种解题思路包括思路讲解、实现代码以及复杂度分析;
  • 知识回忆:针对今天介绍的题目中的重点内容、数据结构进行回顾总结。

Tag

【矩阵】【数组】


题目来源

54. 螺旋矩阵


题目解读

从矩阵左上角 (0, 0) 位置开始,按照顺时针旋转方向螺旋遍历依次输出矩阵的所有元素。


解题思路

方法一:模拟

本题一个直观的思路就是按照要求进行模拟。按照 “向右-向下-向左-向上” 的顺序遍历矩阵,读取每个位置的元素到答案数组中。

几个方向上的移动,可以通过坐标加减来实现,设当前位置坐标(行号和列号)为 (x, y),接下来是四个方向移动的坐标变换:

  • 向右:x 不变,y += 1
  • 向下:x += 1y 不变;
  • 向左:x 不变,y -= 1
  • 向上:x -= 1y 不变;

于是,定义一个表示方向的二维数组 dirs[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}},注意第一维表示的方向要与 “向右-向下-向左-向上” 顺序一一对应。

我们还要使用一个数组 visited 来记录当前位置是否遍历过,如果遍历过,我们也要改变遍历的方向,因为要求是螺旋遍历输出所有的元素。

当前的移动方向索引用 dirIdx 表示,初始 dirIdx = 0 表示向右移动。我们从 (0, 0) 位置出发:

  • 将读取到的位置 (row, col) 对应的元素存入答案数组;
  • 更新数组 visited[row][col] = 1
  • 更新下一个将要遍历的位置即 nrow = row + dirs[dirIdx][0]ncol = col + dirs[dirIdx][1]
  • 如果下一个遍历的位置超出了矩阵的边界或者是已经遍历过的位置,那就要改变移动位置方向,即改变 dirIdx
  • 更新下一个位置的真正方向;
  • 如此遍历完所有位置,即可得到最后的答案数组。

实现代码

class Solution {
public:vector<int> spiralOrder(vector<vector<int>>& matrix) {int m = matrix.size(), n = matrix[0].size();vector<int> ret(m*n);const int dirs[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};int dirIdx = 0;int visited[m][n];memset(visited, 0, sizeof(visited));int i;int row = 0, col = 0;for(i = 0; i < m*n; ++i) {ret[i] = matrix[row][col];visited[row][col] = 1;int nrow = row + dirs[dirIdx][0];int ncol = col + dirs[dirIdx][1];if(nrow < 0 || nrow >= m || ncol < 0 || ncol >= n || visited[nrow][ncol]) {dirIdx = (dirIdx + 1) % 4;               }row += dirs[dirIdx][0];col += dirs[dirIdx][1];}return ret;}
};

复杂度分析

时间复杂度: O ( m n ) O(mn) O(mn) m m m 为矩阵 matrix 的行数, n n n 为列数。

空间复杂度: O ( 1 ) O(1) O(1)

方法二:按层模拟

可以将矩阵看成若干层,我们一层一层的输出元素。我们定义第 k 层为距离最近边界距离为 k 的所有顶点。

对于每层,我们从左上角开始以顺时针的顺序遍历所有元素。假设当前层的左上角为 (top, left),右下角为 (buttom, right),按照如下顺序进行遍历:

  • 从左到右遍历当前层的上部元素,(top, left)(top, right)
  • 从上到下遍历当前层的右部元素,(top+1, right)(buttom, right)
  • 如果 left < righttop < buttom,则从右到左遍历下部元素,(buttom, right-1)(buttom, left+1);从下到上遍历左部元素,(buttom, left)(top+1, left)

遍历完当前层的所有元素之后,更新层数为下一层,将 ++left++top--right--bottom。继续遍历,直到遍历完所有元素为止。

实现代码

class Solution {
public:vector<int> spiralOrder(vector<vector<int>>& matrix) {if (matrix.size() == 0 || matrix[0].size() == 0) return {};int rows = matrix.size(), columns = matrix[0].size();vector<int> res;int left = 0, right = columns - 1, top = 0, bottom = rows - 1;	// 初始化为第一层while (left <= right && top <= bottom) {for (int column = left; column <= right; ++column) {		// 更新上部res.push_back(matrix[top][column]);}for (int row = top + 1; row <= bottom; ++row) {				// 更新右部res.push_back(matrix[row][right]);}if (left < right && top < bottom) {for (int column = right - 1; column > left; --column) {	// 更新下部res.push_back(matrix[bottom][column]);}for (int row = bottom; row > top; --row) {				// 更新左部res.push_back(matrix[row][left]);}}// 更新到下一层left++;right--;top++;bottom--;}return res;}
};

复杂度分析

时间复杂度: O ( m n ) O(mn) O(mn) m m m 为矩阵 matrix 的行数, n n n 为列数。

空间复杂度: O ( 1 ) O(1) O(1)


写在最后

如果文章内容有任何错误或者您对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。

如果大家有更优的时间、空间复杂度方法,欢迎评论区交流。

最后,感谢您的阅读,如果感到有所收获的话可以给博主点一个 👍 哦。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据结构】选择排序 堆排序(二)

目录 一&#xff0c;选择排序 1&#xff0c;基本思想 2&#xff0c; 基本思路 3&#xff0c;思路实现 二&#xff0c;堆排序 1&#xff0c;直接选择排序的特性总结&#xff1a; 2&#xff0c;思路实现 3&#xff0c;源代码 最后祝大家国庆快乐&#xff01; 一&#xf…

测试专项笔记(一): 通过算法能力接口返回的检测结果完成相关指标的计算(目标检测)

文章目录 一、任务描述二、指标分析2.1 TP/FP/FN/TN2.2 精准率2.3 召回率 三、接口处理四、数据集处理五、开始计算指标五、实用工具5.1 移动文件5.2 可视化JSON标签5.3 可视化TXT标签 一、任务描述 通过给定的算法接口&#xff0c;对算法的输出&#xff08;置信度、检测框、告…

英飞凌 Tricore 架构中断系统详解

本文以TC3系列MCU为例&#xff0c;先来了解中断源是如何产生的&#xff0c;再看一下CPU是如何处理中断源的。 AURIX TC3XX的中断路由模块 Interrupt Router (IR) 在TC3中&#xff0c;中断既可以被CPU处理&#xff0c;也可以被DMA处理&#xff0c;所以手册中不再把中断称为中断…

Apache Commons Pool2 池化技术

对象池是一种设计模式&#xff0c;用于管理和重用对象&#xff0c;以提高性能和资源利用率。对象池的概念在许多应用程序中都有广泛应用&#xff0c;特别是在需要频繁创建和销毁对象的情况下&#xff0c;例如数据库连接、线程、HTTP连接等 对象池通过预先创建一组对象并将它们存…

【数据结构篇】堆

文章目录 堆前言基本介绍认识堆堆的特点堆的分类堆的操作堆的常见应用 堆的实现JDK 自带的堆手动实现堆 堆 前言 本文主要是对堆的一个简单介绍&#xff0c;如果你是刚学数据结构的话&#xff0c;十分推荐看这篇文章&#xff0c;通过本文你将对堆这个数据结构有一个大致的了解…

阿里云ACP知识点(三)

1、弹性伸缩不仅提供了在业务需求高峰或低谷时自动调节ECS实例数量的能力&#xff0c;而且提供了ECS实例上自动部署应用的能力。弹性伸缩的伸缩配置支持多种特性&#xff0c;例如______,帮助您高效、灵活地自定义ECS实例配置&#xff0c;满足业务需求。 标签、密钥对、 实例RAM…

大学各个专业介绍

计算机类 五米高考-计算机类 注&#xff1a;此处平均薪酬为毕业五年平均薪酬&#xff0c;薪酬数据仅供参考 来源&#xff1a; 掌上高考 电气类 五米高考-电气类 机械类 五米高考-机械类 电子信息类 五米高考-电子信息类 土木类 五米高考-土木类

从零手搓一个【消息队列】实现数据的硬盘管理和内存管理(线程安全)

文章目录 一、硬盘管理1, 创建 DiskDataCenter 类2, init() 初始化3, 封装交换机4, 封装队列5, 关于绑定6, 关于消息 二、内存管理1, 数据结构的设计2, 创建 MemoryDataCenter 类3, 关于交换机4, 关于队列5, 关于绑定6, 关于消息7, 恢复数据 三、小结 创建 Spring Boot 项目, S…

26 docker前后端部署

[参考博客]((257条消息) DockerNginx部署前后端分离项目(SpringBootVue)的详细教程_在docker中安装nginx实现前后端分离_这里是杨杨吖的博客-CSDN博客) (DockerNginx部署前后端分离项目(SpringBootVue)) 安装docker # 1、yum 包更新到最新 yum update # 2、安装需要的软件包…

SEO的优化教程(百度SEO的介绍和优化)

百度SEO关键字介绍&#xff1a; 百度SEO关键字是指用户在搜索引擎上输入的词语&#xff0c;是搜索引擎了解网站内容和相关性的重要因素。百度SEO关键字可以分为短尾词、中尾词和长尾词&#xff0c;其中长尾词更具有针对性和精准性&#xff0c;更易于获得高质量的流量。蘑菇号-…

构建一个TypeScript环境的node项目

本文 我们用一种不太一样的方式来创建项目 这里 我们事先创建了一个文件夹作为项目目录 然后打开项目终端 输入 npm init然后 在新弹出的对话框中 大体就是 名字随便写一个 然后 后面的回车&#xff0c;到最后一个输入 yes 然后回车 这样 我们就有一个基础的 node项目结构了…

AGV小车、机械臂协同作业实战06-任务分配算法(图解蚁群算法)代码示例java

什么是蚁群算法&#xff1f; 蚁群系统(Ant System(AS)或Ant Colony System(ACS))是由意大利学者Dorigo、Maniezzo等人于20世纪90年代首先提出来的。他们在研究蚂蚁觅食的过程中&#xff0c;发现蚁群整体会体现一些智能的行为&#xff0c;例如蚁群可以在不同的环境下&#xff0c…

排序篇(四)----归并排序

排序篇(四)----归并排序 1.归并(递归) 基本思想&#xff1a; 归并排序&#xff08;MERGE-SORT&#xff09;是建立在归并操作上的一种有效的排序算法,该算法是采用分治法&#xff08;Divide andConquer&#xff09;的一个非常典型的应用。将已有序的子序列合并&#xff0c;得到…

Hive SQL初级练习(30题)

前言 Hive 的重要性不必多说&#xff0c;离线批处理的王者&#xff0c;Hive 用来做数据分析&#xff0c;SQL 基础必须十分牢固。 环境准备 建表语句 这里建4张表&#xff0c;下面的练习题都用这些数据。 -- 创建学生表 create table if not exists student_info(stu_id st…

yolov5分割+检测c++ qt 中部署,以opencv方式(详细代码(全)+复制可用)

1&#xff1a;版本说明&#xff1a; qt 5.12.10 opencv 4.5.3 &#xff08;yolov5模型部署要求opencv>4.5.0&#xff09; 2&#xff1a;检测的代码 yolo.h #pragma once #include<iostream> #include<cmath> #include<vector> #include <opencv2/…

毅速课堂:3D打印随形水路在小零件注塑中优势明显

小零件注塑中的冷却不均匀问题常常导致烧焦现象的发生。这主要是因为传统机加工方法无法制造出足够细小的水路&#xff0c;以适应小零件的复杂形状。而3D打印技术的引入&#xff0c;尤其是随形水路的设计&#xff0c;为解决这一问题提供了新的解决方案。 3D打印随形水路技术的优…

TS编译选项——编译TS文件同时对JS文件进行编译

一、允许对JS文件进行编译 我们在默认情况下编译TS项目时是不能编译js文件的&#xff0c;如下图中的hello.js文件并未编译到dist目录下&#xff08;这里配置了编译文件放到dist目录下&#xff09; 如果我们想要实现编译TS文件同时对JS文件进行编译&#xff0c;就需要在tsconfi…

使用U3D、pico开发VR(二)——添加手柄摇杆控制移动

一、将unity 与visual studio 相关联 1.Edit->Preference->External tool 选择相应的版本 二、手柄遥控人物转向和人物移动 1.添加Locomotion System组件 选择XR Origin&#xff1b; 2.添加Continuous Move Provider&#xff08;Action-based&#xff09;组件 1>…

编程每日一练(多语言实现)基础篇:求总数问题

文章目录 一、实例描述二、技术要点三、代码实现3.1 C 语言实现3.2 Python 语言实现3.3 Java 语言实现3.4 JavaScript 语言实现 一、实例描述 集邮爱好者把所有的邮票存放在三个集邮册中&#xff0c;在A册内存放全部的十分之二&#xff0c;在B册内存放不知道是全部的七分之几&…

MyBatis的一级缓存和二级缓存:原理和作用

MyBatis的一级缓存和二级缓存&#xff1a;原理和作用 引言 在数据库访问中&#xff0c;缓存是一种重要的性能优化手段&#xff0c;它可以减少数据库查询的次数&#xff0c;加快数据访问速度。MyBatis作为一款流行的Java持久层框架&#xff0c;提供了一级缓存和二级缓存来帮助…