【LeetCode题目详解】59. 螺旋矩阵 II 54. 螺旋矩阵 LCR 146. 螺旋遍历二维数组(c++)

这篇文章的题目稍微难一点

题目建议:  本题关键还是在转圈的逻辑,在二分搜索中提到的区间定义,在这里又用上了。 

一、59. 螺旋矩阵 II

题目:

给你一个正整数 n ,生成一个包含 1 到 n2 所有元素,且元素按顺时针顺序螺旋排列的 n x n 正方形矩阵 matrix

示例 1:

输入:n = 3
输出:[[1,2,3],[8,9,4],[7,6,5]]

示例 2:

输入:n = 1
输出:[[1]]

提示:

  • 1 <= n <= 20

思路

这道题目可以说在面试中出现频率较高的题目,本题并不涉及到什么算法,就是模拟过程,但却十分考察对代码的掌控能力。

要如何画出这个螺旋排列的正方形矩阵呢?

相信很多同学刚开始做这种题目的时候,上来就是一波判断猛如虎。

结果运行的时候各种问题,然后开始各种修修补补,最后发现改了这里那里有问题,改了那里这里又跑不起来了。

大家还记得我们在这篇文章数组:每次遇到二分法,都是一看就会,一写就废

(opens new window)中讲解了二分法,提到如果要写出正确的二分法一定要坚持循环不变量原则

而求解本题依然是要坚持循环不变量原则。

模拟顺时针画矩阵的过程:

  • 填充上行从左到右
  • 填充右列从上到下
  • 填充下行从右到左
  • 填充左列从下到上

由外向内一圈一圈这么画下去。

可以发现这里的边界条件非常多,在一个循环中,如此多的边界条件,如果不按照固定规则来遍历,那就是一进循环深似海,从此offer是路人

这里一圈下来,我们要画每四条边,这四条边怎么画,每画一条边都要坚持一致的左闭右开,或者左开右闭的原则,这样这一圈才能按照统一的规则画下来。

那么我按照左闭右开的原则,来画一圈,大家看一下:

这里每一种颜色,代表一条边,我们遍历的长度,可以看出每一个拐角处的处理规则,拐角处让给新的一条边来继续画。

这也是坚持了每条边左闭右开的原则。

一些同学做这道题目之所以一直写不好,代码越写越乱。

就是因为在画每一条边的时候,一会左开右闭,一会左闭右闭,一会又来左闭右开,岂能不乱。

代码如下,已经详细注释了每一步的目的,可以看出while循环里判断的情况是很多的,代码里处理的原则也是统一的左闭右开。

整体C++代码如下:

class Solution {
public:vector<vector<int>> generateMatrix(int n) {vector<vector<int>> res(n, vector<int>(n, 0)); // 使用vector定义一个二维数组int startx = 0, starty = 0; // 定义每循环一个圈的起始位置int loop = n / 2; // 每个圈循环几次,例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理int mid = n / 2; // 矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)int count = 1; // 用来给矩阵中每一个空格赋值int offset = 1; // 需要控制每一条边遍历的长度,每次循环右边界收缩一位int i,j;while (loop --) {i = startx;j = starty;// 下面开始的四个for就是模拟转了一圈// 模拟填充上行从左到右(左闭右开)for (j = starty; j < n - offset; j++) {res[startx][j] = count++;}// 模拟填充右列从上到下(左闭右开)for (i = startx; i < n - offset; i++) {res[i][j] = count++;}// 模拟填充下行从右到左(左闭右开)for (; j > starty; j--) {res[i][j] = count++;}// 模拟填充左列从下到上(左闭右开)for (; i > startx; i--) {res[i][j] = count++;}// 第二圈开始的时候,起始位置要各自加1, 例如:第一圈起始位置是(0, 0),第二圈起始位置是(1, 1)startx++;starty++;// offset 控制每一圈里每一条边遍历的长度offset += 1;}// 如果n为奇数的话,需要单独给矩阵最中间的位置赋值if (n % 2) {res[mid][mid] = count;}return res;}
};
  • 时间复杂度 O(n^2): 模拟遍历二维矩阵的时间
  • 空间复杂度 O(1)
  • 类似题目

  • 54.螺旋矩阵
  • (opens new window)
  • 剑指Offer 29.顺时针打印矩阵
  • (opens new window)

二、54. 螺旋矩阵

题目:

给你一个 mn 列的矩阵 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

题解:

两种题解:一种是根据上面那一题的思路去改的,稍微复杂一点

class Solution {
public:vector<int> spiralOrder(vector<vector<int>>& matrix) {if (matrix.size() == 0 || matrix[0].size() == 0) {return {};}vector<int> res;int i, j;int m = matrix.size(), n = matrix[0].size();int startx = 0, starty = 0;int offset = 1;// 特判:只有一行if (m == 1) {return matrix[0];}// 特判:只有一列if (n == 1) {for (i = 0; i < m; i++) {res.push_back(matrix[i][0]);}return res;}while (startx <= n - offset && starty <= m - offset) {i = startx;j = starty;for (j = starty; j < n - offset && res.size() < m * n; j++) {res.push_back(matrix[i][j]);}for (i = startx; i < m - offset && res.size() < m * n; i++) {res.push_back(matrix[i][j]);}for (; j > starty && res.size() < m * n; j--) {res.push_back(matrix[i][j]);}for (; i > startx && res.size() < m * n; i--) {res.push_back(matrix[i][j]);}startx++;starty++;offset += 1;}if (res.size() < m * n) {if (n % 2 && m % 2) {res.push_back(matrix[i][j]);} else if (n % 2) {for (; i >= startx && res.size() < m * n; i--) {res.push_back(matrix[i][j]);}} else if (m % 2) {for (; j >= starty && res.size() < m * n; j--) {res.push_back(matrix[i][j]);}}}return res;}
};

第二种是力扣上的题解,比较简洁一点

可以将矩阵看成若干层,首先输出最外层的元素,其次输出次外层的元素,直到输出最内层的元素。

定义矩阵的第 kkk 层是到最近边界距离为 kkk 的所有顶点。例如,下图矩阵最外层元素都是第 111 层,次外层元素都是第 222 层,剩下的元素都是第 333 层。

[[1, 1, 1, 1, 1, 1, 1],
 [1, 2, 2, 2, 2, 2, 1],
 [1, 2, 3, 3, 3, 2, 1],
 [1, 2, 2, 2, 2, 2, 1],
 [1, 1, 1, 1, 1, 1, 1]]

对于每层,从左上方开始以顺时针的顺序遍历所有元素。假设当前层的左上角位于 (top,left)(\textit{top}, \textit{left})(top,left),右下角位于 (bottom,right)(\textit{bottom}, \textit{right})(bottom,right),按照如下顺序遍历当前层的元素。

    从左到右遍历上侧元素,依次为 (top,left)(\textit{top}, \textit{left})(top,left) 到 (top,right)(\textit{top}, \textit{right})(top,right)。

    从上到下遍历右侧元素,依次为 (top+1,right)(\textit{top} + 1, \textit{right})(top+1,right) 到 (bottom,right)(\textit{bottom}, \textit{right})(bottom,right)。

    如果 left<right\textit{left} < \textit{right}left<right 且 top<bottom\textit{top} < \textit{bottom}top<bottom,则从右到左遍历下侧元素,依次为 (bottom,right−1)(\textit{bottom}, \textit{right} - 1)(bottom,right−1) 到 (bottom,left+1)(\textit{bottom}, \textit{left} + 1)(bottom,left+1),以及从下到上遍历左侧元素,依次为 (bottom,left)(\textit{bottom}, \textit{left})(bottom,left) 到 (top+1,left)(\textit{top} + 1, \textit{left})(top+1,left)。

遍历完当前层的元素之后,将 left\textit{left}left 和 top\textit{top}top 分别增加 111,将 right\textit{right}right 和 bottom\textit{bottom}bottom 分别减少 111,进入下一层继续遍历,直到遍历完所有元素为止。

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> order;int left = 0, right = columns - 1, top = 0, bottom = rows - 1;while (left <= right && top <= bottom) {for (int column = left; column <= right; column++) {order.push_back(matrix[top][column]);}for (int row = top + 1; row <= bottom; row++) {order.push_back(matrix[row][right]);}if (left < right && top < bottom) {for (int column = right - 1; column > left; column--) {order.push_back(matrix[bottom][column]);}for (int row = bottom; row > top; row--) {order.push_back(matrix[row][left]);}}left++;right--;top++;bottom--;}return order;}
};

复杂度分析

    时间复杂度:O(mn)O(mn)O(mn),其中 mmm 和 nnn 分别是输入矩阵的行数和列数。矩阵中的每个元素都要被访问一次。

    空间复杂度:O(1)O(1)O(1)。除了输出数组以外,空间复杂度是常数。

三、LCR 146. 螺旋遍历二维数组

题目:

给定一个二维数组 array,请返回「螺旋遍历」该数组的结果。

螺旋遍历:从左上角开始,按照 向右向下向左向上 的顺序 依次 提取元素,然后再进入内部一层重复相同的步骤,直到提取完所有元素。

示例 1:

输入:array = [[1,2,3],[8,9,4],[7,6,5]]
输出:[1,2,3,4,5,6,7,8,9]

示例 2:

输入:array  = [[1,2,3,4],[12,13,14,5],[11,16,15,6],[10,9,8,7]]
输出:[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]

限制:

  • 0 <= array.length <= 100
  • 0 <= array[i].length <= 100

注意:本题与主站 54 题相同:. - 力扣(LeetCode)

题解:

这一题基本和上面那一题一样

class Solution {public int[] spiralArray(int[][] array) {if (array == null || array.length == 0 || array[0].length == 0) {return new int[0];}int rows = array.length, columns = array[0].length;int[] order = new int[rows * columns];int index = 0;int left = 0, right = columns - 1, top = 0, bottom = rows - 1;while (left <= right && top <= bottom) {for (int column = left; column <= right; column++) {order[index++] = array[top][column];}for (int row = top + 1; row <= bottom; row++) {order[index++] = array[row][right];}if (left < right && top < bottom) {for (int column = right - 1; column > left; column--) {order[index++] = array[bottom][column];}for (int row = bottom; row > top; row--) {order[index++] = array[row][left];}}left++;right--;top++;bottom--;}return order;}
}

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

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

相关文章

DataX的安装使用

DataX概述&#xff1a; DataX 是阿里巴巴集团内被广泛使用的离线数据同步工具/平台&#xff0c;实现包括 MySQL、Oracle、HDFS、Hive、OceanBase、HBase、OTS、ODPS 等各种异构数据源之间高效的数据同步功能。DataX采用了框架 插件 的模式&#xff0c;目前已开源&#xff0c;代…

如何用GPT制作PPT和写代码?

详情点击链接&#xff1a;如何用GPT制作PPT和写模型代码&#xff1f; 一OpenAI 1.最新大模型GPT-4 Turbo 2.最新发布的高级数据分析&#xff0c;AI画图&#xff0c;图像识别&#xff0c;文档API 3.GPT Store 4.从0到1创建自己的GPT应用 5. 模型Gemini以及大模型Claude2二定…

【Docker】快速入门之Docker的安装及使用

一、引言 1、什么是Docker Docker是一个开源的应用容器引擎&#xff0c;它让开发者可以将他们的应用及其依赖打包到一个可移植的镜像中&#xff0c;然后发布到任何流行的Linux或Windows操作系统的机器上&#xff0c;也可以实现虚拟化。容器是完全使用沙箱机制&#xff0c;相互之…

软件测试|使用pillow给图片添加水印

简介 水印是一种在图片上添加文字或图像的技术&#xff0c;用于标识图片的来源、版权信息或其他附加信息。Pillow 是一个强大的 Python 图像处理库&#xff0c;它提供了许多功能&#xff0c;包括给图片添加水印。本文将详细介绍如何使用 Pillow 给图片添加水印。 创建水印 在…

SpringBoot中整合ElasticSearch快速入门以及踩坑记录

场景 若依前后端分离版手把手教你本地搭建环境并运行项目&#xff1a; 若依前后端分离版手把手教你本地搭建环境并运行项目_本地运行若依前后端分离-CSDN博客 参考上面搭建项目。 ElaticSearch Elasticsearch 是java开发的&#xff0c;基于 Lucene 的搜索引擎。它提供了一…

Android perfetto memory开源工具分析

目录 原理 官网链接 下载heap_profile producer_support.cc 本地编译 push heapprofd 工具使用 pb文件获取 打开*.pb文件 trace文件 提高系统CPU性能 拆解特定函数内存占用 环境配置 工具使用 修改heap_profile 脚本 原理 Android perfetto memory分析工具和ma…

QT图表-折线图、曲线图

时间记录&#xff1a;2024/1/15 一、使用步骤 1.添加图表模块 .pro项目管理文件中添加charts模块 QChart类&#xff1a;图表类 QChartView类&#xff1a;图表显示类 2.ui文件中添加QChartView组件 &#xff08;1&#xff09;选择一个QGrapicsView组件将其拖拽到ui界面上合适位…

pandas查看数据常用方法(以excel为例)

目录 1.查看指定行数的数据head() 2. 查看数据表头columns 3.查看索引index 4.指定索引列index_col 5.按照索引排序 6.按照数据列排序sort_values() 7.查看每列数据类型dtypes 8.查看指定行列数据loc 9.查看数据是否为空isnull() 1.查看指定行数的数据head() &#xff…

二分图带权最大匹配-KM算法详解

文章目录 零、前言一、红娘再牵线二、二分图带权最大完备匹配2.1二分图带权最大匹配2.2概念2.3KM算法2.3.1交错树2.3.2顶标2.3.3相等子图2.3.4算法原理2.3.5算法实现 三、OJ练习3.1奔小康赚大钱3.2Ants 零、前言 关于二分图&#xff1a;二分图及染色法判定-CSDN博客 关于二分…

JVM 一些重要配置参数

1、内存配置参数 -Xmx<size>&#xff1a;设置Java堆的最大内存。如 -Xmx2g 将堆的最大大小设置为2G&#xff0c;推荐配置为系统可用内存的70-80%-Xms<size>&#xff1a;设置Java堆的初始内存。如 -Xms2g 将堆的初始大小设置为2G&#xff0c;推荐配置与-Xmx的值相同…

华为云优惠券介绍、种类、领取入口及使用教程

华为云作为国内领先的云服务提供商&#xff0c;为了吸引用户&#xff0c;经常推出各种优惠活动&#xff0c;其中就包括华为云优惠券。通过领取和使用优惠券&#xff0c;可以降低用户上云成本&#xff0c;提升用户上云的使用体验。本文将详细介绍华为云的优惠券&#xff0c;包括…

Notepad++安装步骤

Notepad是一款文本编辑工具&#xff0c;支持27种编程语言&#xff0c;通吃C,C ,Java ,C#, XML, HTML, PHP,JS 等&#xff0c;该软件拥有完整的中文化接口及支持多国语言编写的功能&#xff0c;不仅可以用来制作一般的纯文字说明文件&#xff0c;还非常适合编写计算机程序代码&a…

2024年,如何打造惊艳的个人博客/出版系统并且赚点小钱?

几年前&#xff0c;我就推荐过用Markdown写作静态博客。静态博客几乎是零托管成本&#xff0c;比较适合个人博客起步。Markdown便于本地搜索&#xff0c;也可当作是个人知识库方案。 现在有了新的进展。我不仅构建了一个视觉上相当不错的个人网站&#xff0c;还美化了github、…

Mybatis配置动态数据源以及参数传递等

Mybatis必知必会 一、Mybatis动态加载数据源 在配置数据源连接时,在企业的真实开发中数据源一般都会写在配置文件中&#xff0c;而不会直接写在mybatis的核心配置文件中 所以,Mybatis为了方便开发人员去动态的获取数据源连接制定了一些特定的标签用于加载这些数据源。 具体做法…

c语言题目之斐波那契数列

文章目录 题目一、什么叫斐波那契数列1&#xff0c;由来2&#xff0c;定义 二、代码编写总结 题目 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、什么叫斐波那契数列 1&#xff0c;由来 在数学历史上&#xff0c;欧洲黑暗时期过后&#xff0c;第…

web3d-three.js场景设计器-sprite广告牌

three.js使用Sprite精灵实现文字或者图片广告牌1.将文字绘制到Canvas&#xff0c;调整对应宽高。2.作为Cavans材质绑定到Sprite3.加载到场景调整适当的scale function createLabel({ text, fontSize, textColor, color, imageUrl }) { return new Promise((resolve, reject) &…

数据结构学习 jz66 构建乘积数组

关键词&#xff1a;数学 双指针 方法一&#xff1a;这个题目我一开始做不知道不能用除法。我做的&#xff1a;[ 用时: 12 m 12 s ] 用了除法 分类讨论 方法二&#xff1a;后来看了提示&#xff0c;双指针&#xff0c;两边各开始乘。 方法三&#xff1a;然后又看了答案可以节…

vue 使用mock模拟数据

vue 使用mock模拟数据 安装依赖 cnpm install axios --save cnpm install mockjs --save-dev cnpm install json5 --save-dev在根目录下&#xff0c;新建一个mock文件&#xff0c;且创建如下文件 utils.js index.js const Mock require(mockjs) const { param2Obj } …

基于selenium的pyse自动化测试框架

介绍&#xff1a; pyse基于selenium&#xff08;webdriver&#xff09;进行了简单的二次封装&#xff0c;比selenium所提供的方法操作更简洁。 特点&#xff1a; 默认使用CSS定位&#xff0c;同时支持多种定位方法&#xff08;id\name\class\link_text\xpath\css&#xff09…