【数组】leetcode59.螺旋矩阵II(C/C++/Java/Js)

news/2024/10/27 21:12:34/

leetcode59.螺旋矩阵II

  • 1 题目
  • 2 思路
  • 3 代码
    • 3.1 C++版本
    • 3.2 C版本
    • 3.3 Java版本
    • 3.4 JavaScript版本
  • 4 总结:

1 题目

题源链接

给你一个正整数 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


2 思路

这道题实际上也就是要处理好各种判断的边界条件,模拟整个顺时针螺旋画矩阵的过程。

  1. 从左到右填充上行;
  2. 从上到下填充右列;
  3. 从右到左填充下行;
  4. 从下到上填充左列;

对此题没太多思路的同学可以去看。Carl老师的视频讲解

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

那么我按照左闭右开的原则,来画一圈,大家看一下:
在这里插入图片描述
每一种颜色,代表一条边,我们遍历的长度,可以看出每一个拐角处的处理规则,拐角处让给新的一条边来继续画。

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


3 代码

3.1 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;}
};

3.2 C版本

/*** Return an array of arrays of size *returnSize.* The sizes of the arrays are returned as *returnColumnSizes array.* Note: Both returned array and *columnSizes array must be malloced, assume caller calls free().*/
int** generateMatrix(int n, int* returnSize, int** returnColumnSizes){//初始化返回的结果数组的大小*returnSize = n;*returnColumnSizes = (int*)malloc(sizeof(int) * n);//初始化返回结果数组ansint** ans = (int**)malloc(sizeof(int*) * n);int i;for(i = 0; i < n; i++) {ans[i] = (int*)malloc(sizeof(int) * n);(*returnColumnSizes)[i] = n;}//设置每次循环的起始位置int startX = 0;int startY = 0;//设置二维数组的中间值,若n为奇数。需要最后在中间填入数字int mid = n / 2;//循环圈数int loop = n / 2;//偏移数int offset = 1;//当前要添加的元素int count = 1;while(loop) {int i = startX;int j = startY;//模拟上侧从左到右for(; j < startY + n - offset; j++) {ans[startX][j] = count++;}//模拟右侧从上到下for(; i < startX + n - offset; i++) {ans[i][j] = count++;}//模拟下侧从右到左for(; j > startY; j--) {ans[i][j] = count++;}//模拟左侧从下到上for(; i > startX; i--) {ans[i][j] = count++;}//偏移值每次加2offset+=2;//遍历起始位置每次+1startX++;startY++;loop--;}//若n为奇数需要单独给矩阵中间赋值if(n%2)ans[mid][mid] = count;return ans;
}

3.3 Java版本

class Solution {public int[][] generateMatrix(int n) {int loop = 0;  // 控制循环次数int[][] res = new int[n][n];int start = 0;  // 每次循环的开始点(start, start)int count = 1;  // 定义填充数字int i, j;while (loop++ < n / 2) { // 判断边界后,loop从1开始// 模拟上侧从左到右for (j = start; j < n - loop; j++) {res[start][j] = count++;}// 模拟右侧从上到下for (i = start; i < n - loop; i++) {res[i][j] = count++;}// 模拟下侧从右到左for (; j >= loop; j--) {res[i][j] = count++;}// 模拟左侧从下到上for (; i >= loop; i--) {res[i][j] = count++;}start++;}if (n % 2 == 1) {res[start][start] = count;}return res;}
}

3.4 JavaScript版本

/*** @param {number} n* @return {number[][]}*/
var generateMatrix = function(n) {let startX = startY = 0;   // 起始位置let loop = Math.floor(n/2);   // 旋转圈数let mid = Math.floor(n/2);    // 中间位置let offset = 1;    // 控制每一层填充元素个数let count = 1;     // 更新填充数字let res = new Array(n).fill(0).map(() => new Array(n).fill(0));while (loop--) {let row = startX, col = startY;// 上行从左到右(左闭右开)for (; col < startY + n - offset; col++) {res[row][col] = count++;}// 右列从上到下(左闭右开)for (; row < startX + n - offset; row++) {res[row][col] = count++;}// 下行从右到左(左闭右开)for (; col > startY; col--) {res[row][col] = count++;}// 左列做下到上(左闭右开)for (; row > startX; row--) {res[row][col] = count++;}// 更新起始位置startX++;startY++;// 更新offsetoffset += 2;}// 如果n为奇数的话,需要单独给矩阵最中间的位置赋值if (n % 2 === 1) {res[mid][mid] = count;}return res;
};

4 总结:

前面思路中的东西很重要。坚持循环不变量原则
代码里给出的处理原则都是统一的左闭右开。
而且通过代码可以看到模拟这个过程比较重要的变量有:

startx,starty :定义每循环一个圈的起始位置;

loop = n / 2 :指定每个圈循环几次;例如n为奇数3,那么loop = 1 只是循环一圈,矩阵中间的值需要单独处理

mid = n / 2 :矩阵中间的位置,例如:n为3, 中间的位置就是(1,1),n为5,中间位置为(2, 2)

count = 1 : 用来给矩阵中每一个空赋值

offset = 1 :需要控制每一条边遍历的长度,每次循环右边界收缩一位,可以在for中看到。

还有别忘记如果n为奇数时,对最中心的位置赋值。


By --Suki 2022/1/5


http://www.ppmy.cn/news/9783.html

相关文章

uniapp中引入vant Weapp

Vant Weapp官&#xff1a;https://vant-contrib.gitee.io/vant-weapp/#/home 步骤一&#xff1a;下载vant组件插件 从github上下载该插件https://github.com/youzan/vant-weapp 只要这个dist文件夹&#xff0c;把dist重命名为vant&#xff1b; 步骤二&#xff1a; 与pages…

【C++】stack、queue和deque

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《吃透西嘎嘎》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;stack 的…

论 G1 收集器的架构和如何做到回收时间用户设定

目录G1 概念JVM的内存分代假设让用户设置应用的暂停时间G1 概念 G1其实是Garbage First的意思&#xff0c;它不是垃圾优先的意思&#xff0c;而是优先处理那些垃圾多的内存块的意思。 在大的理念上&#xff0c;它还是遵循JVM的内存分代假设。 JVM的内存分代假设 JVM的内存分代…

Go语言context包源码剖析

context包的作用 context包是在go1.7版本中引入到标准库中的 context可以用来在goroutine之间传递上下文信息&#xff0c;相同的context可以传递给运行在不同goroutine中的函数&#xff0c;上下文对于多个goroutine同时使用是安全的&#xff0c;context包定义了上下文类型&am…

【C语言】交换奇偶位和 offsetof 宏的实现

​&#x1f320; 作者&#xff1a;阿亮joy. &#x1f386;专栏&#xff1a;《阿亮爱刷题》 &#x1f387; 座右铭&#xff1a;每个优秀的人都有一段沉默的时光&#xff0c;那段时光是付出了很多努力却得不到结果的日子&#xff0c;我们把它叫做扎根 目录&#x1f449;交换奇偶…

Trie 字典树

Trie Trie&#xff0c;又称字典树或前缀树。是一棵有根的多叉树。用于高效存储和查找字符串集合。 字典树从根到树上某一结点的路径就是一个字符串。 一棵字典树的构造过程图解&#xff1a; 字典树的度和字符集有关&#xff0c;英文字符集是26个字母&#xff0c;那么字典树的…

Redis过期键删除策略

Redis过期键删除策略 第一章 Redis单线程为什么这么快&#xff1f; 第二章 Redis的持久化机制 第三章 Redis过期键的删除策略 Redis过期键删除策略Redis过期键删除策略前言一、惰性过期二、定时过期&#xff08;Redis中没有用到&#xff09;三、定期清理总结前言 想必大家都直…

Android 虚拟分区详解(四) 编译开关

Android Virtual A/B 系统简称 VAB,我将其称为虚拟分区。 本系列文章基于 Android R(11) 进行分析,如果没有特别说明,均基于代码版本 android-11.0.0_r46 请已经购买《Android 虚拟分区》专栏的朋友加我 wx 进 "虚拟分区专栏 VIP 答疑"群,作为本专栏文章的附加服…