螺旋矩阵的算法刷题

螺旋矩阵的算法刷题

本文主要涉及螺旋矩阵的算法
包括三个题目分别是

  1. 59. 螺旋矩阵 II
  2. 54. 螺旋矩阵 中等
  3. LCR 146. 螺旋遍历二维数组

文章目录

  • 螺旋矩阵的算法刷题
    • 一 、螺旋矩阵简单
      • 1.1 实现一(我认为这个方法更巧妙!!)
      • 1.2 实现二(经典方法--更加直观)
    • 二、螺旋矩阵 中等
      • 2.1 实现一(经典)
      • 2.2 实现二(精妙!!)
    • 三、螺旋遍历矩阵 简单

一 、螺旋矩阵简单

59. 螺旋矩阵 II

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

在这里插入图片描述

1.1 实现一(我认为这个方法更巧妙!!)

思路
采用了类似螺旋走位的方式进行填充,具体实现如下:

  1. 首先,定义一个n x n的二维数组res来存储结果。
  2. 初始化方向向量dx和dy,初始值分别为0和1,表示向右移动。
  3. 初始化坐标x和y,初始值都为0,表示从矩阵的左上角开始填充。
  4. 使用一个循环,从1到n * n遍历每个要填充的数字。
  5. 在每一步中,将当前位置的值设置为当前遍历的数字i,并根据当前方向向量(dx, dy)进行移动到下一个位置。
  6. 判断下一个位置是否已经被填充过,如果是,则表示已经到达边界,需要调转方向向量以继续填充;如果不是,则继续沿当前方向向量移动。
  7. 返回填充完成的二维数组res作为结果。

这样的算法可以确保填充的数字形成了一个螺旋状的矩阵。

C++代码实现

class Solution {
public:vector<vector<int>> generateMatrix(int n) {vector<vector<int>> matrix(n,vector<int>(n,0));//代表方向的向量变量 01--右 10--下 -1 0--左 0 -1 --上int dx=0,dy=1;//x,y表示当前坐标int x=0,y=0;//使用for进行循环,i表示当前值for(int i =1; i<=n*n;i++){matrix[x][y]=i;//**关键部分**if(matrix[(x+dx+n)%n][(y+dy+n)%n]!=0)//判断是否已经填充,如果已经填充则向量需要换方向{int temp = dy;dy=-dx;dx=temp;}x+=dx;y+=dy;}return matrix;    }
};

重要的是下面这段代码

 if(matrix[(x+dx+n)%n][(y+dy+n)%n]!=0)//判断是否已经填充,如果已经填充则向量需要换方向{int temp = dy;dy=-dx;dx=temp;}

这段代码是在判断当前位置的下一个位置是否已经被填充过。如果下一个位置已经被填充过,说明当前位置已经是当前层的最后一个位置,需要改变填充方向。

逐行解释这段代码:

  1. (x + dx + n) % n:这里计算了下一个位置的横坐标。由于是螺旋填充,因此下一个位置可能超出边界。使用 % n 可以将超出边界的情况转化为在边界内的情况。例如,当 x + dx 大于等于 n 时,超出了右边界,通过 % n 可以将其映射到左边界,从而形成循环填充。
  2. 同理,(y + dy + n) % n 计算了下一个位置的纵坐标。
  3. res[(x + dx + n) % n][(y + dy + n) % n] != 0:这个条件判断当前位置的下一个位置是否已经被填充过。如果下一个位置不等于0,说明已经被填充过。
  4. 如果下一个位置已经被填充过,则需要改变填充方向。通过交换 dxdy 实现了向下转向的功能。
  5. int tem = dy; dy = -dx; dx = tem;:这里使用了一个临时变量 tem,先将 dy 的值保存下来,然后将 dy 设置为 -dxdx 设置为 tem,实现了方向的转换。

在这里插入图片描述

总的来说,这段代码的作用是在当前位置的下一个位置已经被填充过时,改变填充方向,从而继续填充螺旋矩阵。

1.2 实现二(经典方法–更加直观)

一个常见的方法是按层次遍历,逐层填充螺旋矩阵。具体步骤如下:

  1. 初始化一个n x n的二维数组res,用于存储结果。
  2. 定义四个变量top、bottom、left、right,分别表示当前填充层的上下左右边界。
  3. 初始化这些边界值:top=0,bottom=n-1,left=0,right=n-1。
  4. 初始化一个变量num,表示当前要填充的数字,初始值为1。
  5. 在一个循环中,依次填充每一层的数字,直到所有位置都被填充为止。
    • 从左到右,将当前层的最上一行从left到right填充为num开始递增的数字,同时更新top的值使其向下移动一行。
    • 从上到下,将当前层的最右一列从top到bottom填充为num开始递增的数字,同时更新right的值使其向左移动一列。
    • 从右到左,将当前层的最下一行从right到left填充为num开始递增的数字,同时更新bottom的值使其向上移动一行。
    • 从下到上,将当前层的最左一列从bottom到top填充为num开始递增的数字,同时更新left的值使其向右移动一列。
    • 每填充完一行或一列后,将num递增。
  6. 当top > bottom 或 left > right时,表示所有位置都被填充完毕,退出循环。
  7. 返回填充完成的二维数组res作为结果。

这样的实现方法更直观清晰,容易理解和实现,并且效率也很高。

class Solution {
public:vector<vector<int>> generateMatrix(int n) {vector<vector<int>> res(n, vector<int>(n, 0)); // 初始化结果矩阵为全零int top = 0, bottom = n - 1, left = 0, right = n - 1; // 初始化边界int num = 1; // 当前要填充的数字,初始为1while (true) {// 从左到右,填充最上一行for (int i = left; i <= right; ++i) {res[top][i] = num++;}if (++top > bottom) break; // 更新上边界,若超过下边界则退出// 从上到下,填充最右一列for (int i = top; i <= bottom; ++i) {res[i][right] = num++;}if (--right < left) break; // 更新右边界,若超过左边界则退出// 从右到左,填充最下一行for (int i = right; i >= left; --i) {res[bottom][i] = num++;}if (--bottom < top) break; // 更新下边界,若超过上边界则退出// 从下到上,填充最左一列for (int i = bottom; i >= top; --i) {res[i][left] = num++;}if (++left > right) break; // 更新左边界,若超过右边界则退出}return res;}
};

二、螺旋矩阵 中等

54. 螺旋矩阵 中等

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

在这里插入图片描述

2.1 实现一(经典)

class Solution {
public:vector<int> spiralOrder(vector<vector<int>>& matrix) {vector<int> ans;if (matrix.empty()) return ans;int m = matrix.size(); // 行数int n = matrix[0].size(); // 列数int top = 0, bottom = m - 1, left = 0, right = n - 1;while (top <= bottom && left <= right) {// 从左到右遍历上边界for (int j = left; j <= right; ++j) {ans.push_back(matrix[top][j]);}++top;// 从上到下遍历右边界for (int i = top; i <= bottom; ++i) {ans.push_back(matrix[i][right]);}--right;// 从右到左遍历下边界if (top <= bottom) { // 防止重复访问上一次遍历的元素for (int j = right; j >= left; --j) {ans.push_back(matrix[bottom][j]);}--bottom;}// 从下到上遍历左边界if (left <= right) { // 防止重复访问上一次遍历的元素for (int i = bottom; i >= top; --i) {ans.push_back(matrix[i][left]);}++left;}}return ans;}
};

按照螺旋顺序遍历二维矩阵。下面是对代码的详细解释:

  1. 首先,定义一个空的整数向量 ans 用于存储遍历结果。
  2. 如果输入的二维矩阵 matrix 为空,直接返回空的结果向量 ans
  3. 获取矩阵的行数 m 和列数 n,以及初始化四个边界变量 topbottomleftright
  4. 在一个循环中,不断遍历矩阵的边界元素,直到边界收缩到无效为止。
    • 从左到右遍历上边界,将上边界的元素依次加入结果向量 ans 中,并将 top 上移一行。
    • 从上到下遍历右边界,将右边界的元素依次加入结果向量 ans 中,并将 right 右移一列。
    • 从右到左遍历下边界,将下边界的元素依次加入结果向量 ans 中,并将 bottom 下移一行(注意要判断 top <= bottom,防止重复遍历)。
    • 从下到上遍历左边界,将左边界的元素依次加入结果向量 ans 中,并将 left 左移一列(注意要判断 left <= right,防止重复遍历)。
  5. 循环结束后,返回结果向量 ans

利用边界变量控制了螺旋顺序的遍历过程,实现了按照螺旋顺序遍历二维矩阵的功能。

2.2 实现二(精妙!!)

下面是一段Python代码:

def spiralOrder(self, matrix: List[List[int]]) -> List[int]:res = []while matrix:# 削头(第一层)res += matrix.pop(0)# 将剩下的逆时针转九十度,等待下次被削matrix = list(zip(*matrix))[::-1]return res

采用了不断“削头”的方式来实现。具体的步骤如下:

  1. 创建一个空列表 res 用于存储螺旋顺序遍历的结果。
  2. 使用 while matrix: 循环来遍历矩阵,直到矩阵为空。
  3. 在每一次循环中,先将矩阵的第一行(即第一层)添加到结果列表 res 中,然后将该行从矩阵中移除。
  4. 接着,将剩下的矩阵逆时针旋转 90 度(将其转置后再沿着竖直方向反转),以便下次循环时能够继续削头。
  5. 重复上述步骤直到矩阵为空。

这种方法的思路简洁,通过不断调整矩阵的结构来实现螺旋顺序遍历,避免了显式的控制遍历方向和边界条件的处理。

在实际代码中,matrix.pop(0) 用于削头,list(zip(*matrix))[::-1] 用于逆时针旋转矩阵。

如果是C++实现类似削头的效果:

#include <vector>class Solution {
public:vector<int> spiralOrder(vector<vector<int>>& matrix) {vector<int> res;while (!matrix.empty()) {// 削头(第一层)for (auto it = matrix[0].begin(); it != matrix[0].end(); ++it) {res.push_back(*it);}matrix.erase(matrix.begin()); // 删除第一行// 将剩下的逆时针转九十度,等待下次被削if (!matrix.empty()) {vector<vector<int>> new_matrix;for (int j = matrix[0].size() - 1; j >= 0; --j) {vector<int> column;for (int i = 0; i < matrix.size(); ++i) {column.push_back(matrix[i][j]);}new_matrix.push_back(column);}matrix = new_matrix;}}return res;}
};

三、螺旋遍历矩阵 简单

LCR 146. 螺旋遍历二维数组

上面这个题是企业题,同类型的题目可以多练习练习~

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

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

相关文章

短视频矩阵系统--技术3年源头迭代

短视频矩阵系统核心技术算法主要包括以下几个方面&#xff1a; 1. 视频剪辑&#xff1a;通过剪辑工具或API从各大短视频平台抓取符合要求的视频。这些视频通常符合某些特定条件&#xff0c;如特定关键词、特定时间段发布的视频、视频点赞评论转发等数据表现良好的视频。 2. 视…

2024年【熔化焊接与热切割】报名考试及熔化焊接与热切割模拟试题

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 熔化焊接与热切割报名考试考前必练&#xff01;安全生产模拟考试一点通每个月更新熔化焊接与热切割模拟试题题目及答案&#xff01;多做几遍&#xff0c;其实通过熔化焊接与热切割作业考试题库很简单。 1、【单选题】…

基于随机森林与LSTM神经网络的住宅用电比较分析及预测 代码+论文 完整毕设

摘要 本文旨在探讨基于随机森林&#xff08;Random Forest&#xff09;与长短期记忆神经网络&#xff08;Long Short-Term Memory, LSTM&#xff09;的住宅用电比较分析及预测方法。随机森林是一种集成学习方法&#xff0c;通过构建多个决策树进行预测&#xff0c;具有较强的鲁…

[疑难杂症2024-002]一个“显而易见“的问题,是如何进入生产环境的?

本文由Markdown语法编辑器编辑完成。 1. 前言 最近在处理一个在医院上线的系统的问题。这个问题&#xff0c;由于关联的模块比较多&#xff0c;至少涉及到3个模块之间的功能调用。因此&#xff0c;协调大家都有时间来排查问题不是很方便。这个问题就拖了有一周左右。医院那边…

钡铼技术R40路由器助力智能船舶航行数据实时传输与分析

钡铼技术R40路由器在智能船舶领域的应用&#xff0c;对于航行数据的实时传输与分析具有重要意义。随着航运业的不断发展和智能化水平的提升&#xff0c;船舶航行数据的及时传输和有效分析对船舶的安全、运营效率等方面至关重要。而引入钡铼技术R40路由器&#xff0c;则可以实现…

libVLC 捕获鼠标、键盘事件

在实现播放器的时候&#xff0c;我们需要捕获键盘、鼠标事件进行视频快进、快退&#xff0c;或者双击全屏/退出全屏窗口、鼠标右键弹出菜单栏。默认情况下&#xff0c;在使用libVLC库的时候&#xff0c;我们无法捕获这些事件&#xff0c;因为我们将Qt的视频窗口传递给了libVLC。…

工厂数据分析系统用这个开源库准没错

ScottPlot是一款简单易用、高度定制、性能卓越的.NET绘图库&#xff0c;支持跨平台操作。除提供标准图表类型外&#xff0c;还支持交互式操作&#xff0c;呈现生动的数据展示。在工厂数字化系统中&#xff0c;可用于生产数据可视化、设备监测和质量控制。无论用于科学研究、数据…

Springboot基础之——自定义starter

引言 在实际开发中&#xff0c;经常会定义一些公共的组件&#xff0c;提供给各个项目团队使用。而在SpringBoot项目中&#xff0c;一般会将这些公共组件封装成SpringBoot的starter。 如果想要自定义starter的话&#xff0c;就要先了解自动配置原理。 1 自动配置原理 1.1 什…

地物波谱库共享网站汇总

ENVI自5.2版本重新梳理了原有的标准波谱库&#xff0c;新增一些物质波谱&#xff0c;在ENVI5.6中存放在…\Harris\ENVI56\ resource\speclib&#xff0c;分别存放在四个文件夹中&#xff0c;储存为ENVI波谱库格式&#xff0c;有两个文件组成&#xff1a;.sli和.hdr。 ENVI保留…

代码随想录——搜索插入位置(Leetcode35)

题目链接 class Solution {public int searchInsert(int[] nums, int target) {int len nums.length;int left 0;int right len - 1;int index -1;while(left < len / 2){if(nums[left] target || target < nums[left]){index left;break;}else{left;}if(nums[ri…

通过Caliper进行压力测试程序,且汇总压力测试问题解决

环境要求 第一步. 配置基本环境 部署Caliper的计算机需要有外网权限;操作系统版本需要满足以下要求:Ubuntu >= 16.04、CentOS >= 7或MacOS >= 10.14;部署Caliper的计算机需要安装有以下软件:python 2.7、make、g++(gcc-c++)、gcc及git。第二步. 安装NodeJS # …

高效 CUDA 调试:将 NVIDIA Compute Sanitizer 与 NVIDIA 工具扩展结合使用并创建自定义工具

高效 CUDA 调试&#xff1a;将 NVIDIA Compute Sanitizer 与 NVIDIA 工具扩展结合使用并创建自定义工具 NVIDIA Compute Sanitizer 是一款功能强大的工具&#xff0c;可以节省您的时间和精力&#xff0c;同时提高 CUDA 应用程序的可靠性和性能。 在 CUDA 环境中调试代码既具有挑…

超详细的fiddler教程

&#x1f345; 视频学习&#xff1a;文末有免费的配套视频可观看 &#x1f345; 关注公众号【互联网杂货铺】&#xff0c;回复 1 &#xff0c;免费获取软件测试全套资料&#xff0c;资料在手&#xff0c;涨薪更快 Fiddler&#xff08;中文名称&#xff1a;小提琴&#xff09;是…

【算法题】三道题理解算法思想--滑动窗口篇

滑动窗口 本篇文章中会带大家从零基础到学会利用滑动窗口的思想解决算法题&#xff0c;我从力扣上筛选了三道题&#xff0c;难度由浅到深&#xff0c;会附上题目链接以及算法原理和解题代码&#xff0c;希望大家能坚持看完&#xff0c;绝对能有收获&#xff0c;大家有更好的思…

win11 安装SIBR 3dgs

1.安装显卡驱动 下载地址&#xff1a; 官方驱动 | NVIDIA下载适用于 GeForce、TITAN、NVIDIA RTX、数据中心、GRID 等 NVIDIA 产品的新驱动。https://www.nvidia.cn/Download/index.aspx?langcn 2.安装cuda 下载地址&#xff1a;如果无法打开&#xff0c;切换.com为.cn&am…

JavaScript基础练习题之计算数组元素的和与平均值

一、如何使用JavaScript计算数组元素的和与平均值&#xff1f; 二、正确的源程序 <!DOCTYPE html> <html><head><meta charset"UTF-8"><title>计算数组元素的和与平均值</title></head><body><h1>计算数组元…

两直线交点算法 C

求两直线交点算法 有中间交点 CD在AB异侧 且AB在CD异侧 AB在CD异侧 但 CD在AB同侧 无中间交点 A B A C A B A D \nobreak AB \times AC \newline AB \times AD ABACABAD 异号 叉乘后相乘小于零 等于零的几种情况 A B C与AB共线 D与AB共线 求交点&#xff0c;可由面积比…

iOS - LLVM的中间代码(IR)

文章目录 iOS - LLVM的中间代码&#xff08;IR&#xff09;1. 转为汇编代码2. 中间代码&#xff08;IR&#xff09;2.1 Objective-C在变为机器代码之前&#xff0c;会被LLVM编译器转换为中间代码&#xff08;Intermediate Representation&#xff09;2.2 可以使用以下命令行指令…

武忠祥《660题》高效刷题包+资料分享

660题的难度书虽然比较难&#xff0c;对于基础的考察比较深入&#xff0c;所以&#xff0c;有没有一种可能&#xff0c;做题太慢&#xff0c;是因为基础不好导致的&#xff01; 所以再继续做下去&#xff0c;就没有什么意义了&#xff0c;因为这就像是用一把钝刀去砍树&#x…