6.5数组--模拟、偏移量-螺旋矩阵

news/2025/3/17 4:22:26/文章来源:https://www.cnblogs.com/7dragonpig/p/18233605

M:59.螺旋矩阵II

题意描述

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

示例 1:

img

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

示例 2:

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

提示:

  • 1 <= n <= 20

思路

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

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

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

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

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

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

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

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

img

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

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

AC代码:

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; j < n - offset; j++) {res[i][j] = count++;}// 模拟填充右列从上到下(左闭右开)for (i; 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;}
};

法二:偏移量法

class Solution {
public:vector<vector<int>> generateMatrix(int n) {vector<vector<int>> res(n , vector<int>(n , 0));//顺序依次为左上右下,一开始向右,因此d=1, 列+1int dx[4] = {-1 , 0 , 1 , 0}, dy[4] = {0 , 1 , 0 , -1};//注意这里循环是以填的数cnt:1~n*n来循环n^2次for(int cnt = 1 , x = 0 , y = 0 , d = 1 ;cnt <= n * n ; cnt++){res[x][y] = cnt;int a = x + dx[d] , b = y + dy[d];if(a < 0 || a >= n || b < 0 || b >= n || res[a][b]){d = (d + 1) % 4;a = x + dx[d] , b = y + dy[d];}x = a , y = b;}return res;}
};

ACwing756.蛇形矩阵

题目描述:

输入两个整数 𝑛 和 𝑚,输出一个 𝑛 行 𝑚 列的矩阵,将数字 1 到 𝑛×𝑚 按照回字蛇形填充至矩阵中。

具体矩阵形式可参考样例。

输入格式

输入共一行,包含两个整数 𝑛 和 𝑚。

输出格式

输出满足要求的矩阵。

矩阵占 𝑛 行,每行包含 𝑚 个空格隔开的整数。

数据范围

1≤𝑛,𝑚≤100

输入样例:

3 3

输出样例:

1 2 3
8 9 4
7 6 5

思路:

设当前位置坐标为(x,y),上、下、左、右方向分别为dr=0 dr=2 dr=3 dr=1
则该位置上、下、左、右的位置所对应的偏移量分别为(x-1,y) (x+1,y) (x,y-1) (x,y+1)
将方向与偏移量的对应关系初始化为两个数组便于引用

1.png

每次执行循环后,判断下一个位置是否到达数组边界,或数组中已经存在元素
若满足上述情况,则改变方向。

AC代码:

#include <bits/stdc++.h>
using namespace std;const int maxn=110;int a[maxn][maxn];  //定义空的二维数组数组
int dx[]={-1,0,1,0},dy[]={0,1,0,-1};  //初始化方向所对应的偏移量的数组int main()
{int n,m;cin>>n>>m;int dr=1,x=0,y=0;  //初始化开始方向为右,初始化开始的位置for(int i=1;i<=n*m;i++){a[x][y]=i;  //存入答案int h=x+dx[dr],l=y+dy[dr];  //定义临时变量存放(x,y)的下一个位置的坐标if(h<0||l<0||h>=n||l>=m||a[h][l]){  //判断dr=(dr+1)%4;h=x+dx[dr],l=y+dy[dr];} x=h,y=l;  //更新(x,y)}for(int i=0;i<n;i++){  //循环打印输出for(int j=0;j<m;j++){cout<<a[i][j]<<" ";}cout<<endl;}return 0;
}

类似题目:ACwing3208.Z字形扫描

题意描述:

在图像编码的算法中,需要将一个给定的方形矩阵进行 𝑍 字形扫描(Zigzag Scan)。

给定一个𝑛×𝑛 的矩阵,𝑍 字形扫描的过程如下图所示:

zig.png

对于下面的 4×4 的矩阵,

1 5 3 9
3 7 5 6
9 4 6 4
7 3 1 3

对其进行 𝑍 字形扫描后得到长度为 16 的序列:1 5 3 9 7 3 9 5 4 7 3 6 6 4 1 3

请实现一个 𝑍 字形扫描的程序,给定一个𝑛×𝑛 的矩阵,输出对这个矩阵进行 𝑍 字形扫描的结果。

输入格式

输入的第一行包含一个整数 𝑛,表示矩阵的大小。

输入的第二行到第 𝑛+1 行每行包含 𝑛 个正整数,由空格分隔,表示给定的矩阵。

输出格式

输出一行,包含 𝑛×𝑛 个整数,由空格分隔,表示输入的矩阵经过 𝑍 字形扫描后的结果。

数据范围

1≤𝑛≤500,
矩阵元素为不超过 1000 的正整数。

输入样例:

4
1 5 3 9
3 7 5 6
9 4 6 4
7 3 1 3

输出样例:

1 5 3 9 7 3 9 5 4 7 3 6 6 4 1 3

分析:

该题以Z字形遍历数组,对于奇数和偶数情况下,边界转向复杂
扩大原二维数组,使边界转向统一

怕.png

观察旋转方向,设初始方向dr = 0
扩大二维数组,遍历满足在原数组范围内时输出

说的话.png

AC代码

#include <bits/stdc++.h>
using namespace std;
const int N=505;int a[2*N][2*N];  //定义时直接扩大int main(){int n;scanf("%d",&n);for(int i=0;i<n;i++){  //初始化二维数组for(int j=0;j<n;j++){scanf("%d",&a[i][j]);}}int dr=0,dx[]={0,1,1,-1},dy[]={1,-1,0,1};  //定义(0,1)的方向dr=0  定义偏移量数组printf("%d ",a[0][0]);  //先将(0,0)位置的数输出int x=0,y=1;  //初始化位置为(0,1)for(int i=0;i<(2*n+1)*n;i++){  //循环遍历扩大后的数组if(x<n&&y<n){printf("%d ",a[x][y]);  //满足在原始数组范围内输出}int l=x+dx[dr],r=y+dy[dr];  //临时变量判断下一个要遍历的格子坐标(l,r)if(dr==0||dr==2||r<0||l<0||r>=n||l>=n){  //如果dr=0或dr=2或(l,r)出界时改变方向dr=(dr+1)%4;l=x+dx[dr],r=y+dy[dr];}x=l,y=r;  //更新(x,y)}return 0;
}

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 题相同:https://leetcode-cn.com/problems/spiral-matrix/

思路1:模拟

AC代码:

class Solution {
public:vector<int> spiralArray(vector<vector<int>>& array){if (array.empty()) return {};int l = 0, r = array[0].size() - 1, t = 0, b = array.size() - 1;vector<int> res;while(true){for (int i = l; i <= r; i++) res.push_back(array[t][i]); // left to rightif (++t > b) break;for (int i = t; i <= b; i++) res.push_back(array[i][r]); // top to bottomif (l > --r) break;for (int i = r; i >= l; i--) res.push_back(array[b][i]); // right to leftif (t > --b) break;for (int i = b; i >= t; i--) res.push_back(array[i][l]); // bottom to topif (++l > r) break;}return res;}
};

思路2:偏移量法

判断路径是否进入之前访问过的位置需要使用一个与输入二维数组大小相同的辅助二维数组visited,其中的每个元素表示该位置是否被访问过。当一个元素被访问时,将 visited 中的对应位置的元素设为已访问。

如何判断路径是否结束?由于二维数组中的每个元素都被访问一次,因此路径的长度即为二维数组中的元素数量,当路径的长度达到二维数组中的元素数量时即为完整路径,将该路径返回。

AC代码:

class Solution {
public:vector<int> spiralArray(vector<vector<int>>& array) {if(array.size() == 0  || array[0].size() == 0)  return {};int r = array.size(),c = array[0].size();vector<vector<bool>> visited(r , vector<bool>(c));int t = r * c;vector<int> res(t);int dx[] = {-1 , 0 , 1, 0}, dy[] = {0 , 1 , 0, -1};for(int i =0 ,a = 0 , b = 0 , d = 1; i < t ; i++ ){res[i] = array[a][b];visited[a][b] = true;int na = a + dx[d] , nb = b + dy[d];if(na< 0 || na >= r || nb < 0 || nb >= c || visited[na][nb]){d = (d + 1) % 4;na = a + dx[d] , nb = b + dy[d];}a = na , b = nb;  }return res;}
};

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

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

相关文章

【Java】JVM字节码分析

Java 字节码是Java源代码编译生成的中间形式,赋予Java跨平台特性,通过对字节码的分析,可以迅速找到代码的性能瓶颈。一、功能 1、工作原理2、解释和运行 jvm本质上是运行在计算机上的程序,负责运行java字节码文件 对字节码文件中的指令,实时的解释成机器码,供计算机执行 …

23柏鹭杯-misc

我记得比赛的时候,misc都是0解。 怎么不算另类的1血呢? help_me实在不会,arm看不了一点消失的钥匙 先看验证逻辑,能够看到generateZipPassword和decryptFlag这两个方法内容不见了通过在apk中寻找半年,找到一个时间不对的classes3.dex,查看hex发现是gz压缩导出解压一下,拿…

云原生时代:从 Jenkins 到 Argo Workflows,构建高效 CI Pipeline

ACK One Serverless Argo 工作流作为全托管的 Argo 工作流服务,可以帮助您实现更大规模、具有更快的运行速度、及更低成本的 CI Pipeline,与 ACK One GitOps[8](Argo CD)、Argo Event 等事件驱动架构可以构建完整的自动化 CI/CD Pipeline。作者:蔡靖 Argo Workflows Argo …

智慧城市的规划与实施:科技引领城市运行效率新飞跃

随着信息技术的飞速发展,智慧城市的构想正逐步成为现实。作为地理信息与遥感领域的研究者,我深知在这一转型过程中,技术的创新与应用是提升城市运行效率的关键。本文旨在探讨如何利用地理信息系统(GIS)、遥感技术、大数据、物联网(IoT)等前沿科技,推动智慧城市的规划与…

WebLogic启动报Could not get the server file lock

报错信息如下:解决: 方法一: 引用:https://blog.51cto.com/hifon/2796939 方法二: 1. 出现问题可能是上次没有正确关闭Weblogic,可到如下目录,执行stopWebLogic.cmd(Windows),或stopWebLogic.sh(Linux) C:\Weblogic14.1.1.0\user_projects\domains\staubli\bin

(数据科学学习手札161)高性能数据分析利器DuckDB在Python中的使用

本文完整代码及附件已上传至我的Github仓库https://github.com/CNFeffery/DataScienceStudyNotes1 简介大家好我是费老师,就在几天前,经过六年多的持续开发迭代,著名的开源高性能分析型数据库DuckDB发布了其1.0.0正式版本。DuckDB具有极强的单机数据分析性能表现,功能丰富,…

ApsaraMQ Copilot for RocketMQ:消息数据集成链路的健康管家

为了帮助用户更高效地使用 RocketMQ,阿里云消息队列 ApsaraMQ 提供了一套名为 RocketMQ Copilot 的辅助工具集。它将专家的实践经验产品化,使得即便是缺乏经验的用户也能迅速掌握 RocketMQ 客户端的正确用法,利用云消息队列 RocketMQ 版的可观测性工具进行监控、并高效地排查…

无缝融合:使用 Python 和 PyFFmpeg 合并视频的完整指南

前言 在当今数字化时代,视频内容无处不在。从社交媒体到在线教育,视频已经成为我们生活中不可或缺的一部分。但是,有时候我们可能需要将多个视频片段合并成一个,创造出更丰富、更有吸引力的内容。而今天,我们将向您展示如何使用 Python 和 PyFFmpeg 工具实现这一目标。 准…

音频剪裁大师:使用 Python 和 ffmpeg 分割音频的完整指南

前言 在音频处理中,有时候我们需要对音频文件进行分割,提取其中的部分内容以满足特定需求。而 Python 提供了许多强大的工具和库来实现这一目标,其中 ffmpeg 是一个功能强大的工具,它不仅支持音频分割,还能进行音频转码、合并、提取等操作。本文将介绍如何使用 Python 和 …

正则 .*? 和 .* 的区别是什么

在正则表达式中,.* 和 .*? 的区别在于它们的贪婪程度: .* 是贪婪的,意味着它会尽可能多地匹配字符,直到没有更多字符可匹配。 .*? 是非贪婪的(或懒惰的),意味着它会尽可能少地匹配字符,一旦找到满足整体模式的最小匹配,就会停止。 举例说明: 对于字符串 123456 和模…

钉钉机器人远程重启系统服务

from flask import Flask, request import subprocessapp = Flask(__name__)@app.route(/send_message, methods=[GET]) def send_message():webhook_url = https://oapi.dingtalk.com/robot/send?access_token=YOUR_TOKEN    # YOUR_TOKEN是钉钉机器人的hookmessage = {&…