关于螺旋矩阵

这是我曾经遇到过的面试题,在 LeetCode 上找到了题目的原型,难度中等。题目描述如下:

给定一个包含 m x n 个元素的矩阵(m 行, n 列),请按照顺时针螺旋顺序,返回矩阵中的所有元素。

示例 1:

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

示例 2:

输入:
[
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12]
]
输出: [1,2,3,4,8,12,11,10,9,5,6,7]

解题思路

[[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]]

这是一道难度中等的题目,但是第一次看到题目时还是有一些困惑,不过仔细分析后很容易找到思路。比较直观的思路是逐层法,从外向内循环每一层。其中单层循环的方法也有很多,我使用了插入法循环每一层。以下是 4X4 矩阵循环的步骤:

/**
* --------------------------------------------
* 以 4X4 矩阵为例
*
* [[ 1, 2, 3, 4],
* [ 5, 6, 7, 8],
* [ 9,10,11,12],
* [13,14,15,16]]
*
* --------------------------------------------
* 循环第一层
*
* [[ 1, 2, 3, 4], | 1
* [ 5, 8], | 2
* [ 9, 12], | 3
* [13,14,15,16]] ▼ 4
*
* --------------------------------------------
* 将元素按顺序插入数组,`|` 表示插入位置
*
* [ 1, 2, 3, 4, |]
* (8, 5)┘
*
* [ 1, 2, 3, 4, 8, |, 5]
* (12, 9)┘
*
* [ 1, 2, 3, 4, 8, 12, |, 9, 5]
* (16, 15, 14, 13)┘
*
* [ 1, 2, 3, 4, 8, 12, 16, 15, 14, 13, 9, 5]
*
* 第一层循环结束
*
*/

通过以上步骤拆分,可以看到输出螺旋矩阵还是比较容易的,以下是具体的 JS 代码。

/**
* @param {number[][]} matrix
* @return {number[]}
*/
var spiralOrder = function(matrix) {
// 最终返回的结果数组
var ans = []; var spiralLoop = function() {
// 临时数组
var arr = []; for (var i = 0; i < matrix.length; i++) { if (i === 0) {
arr = arr.concat(matrix[0]);
} if (i > 0 && i < matrix.length - 1) {
var insertRight = matrix[0].length === 1 ?
[] :
arr.splice(-(i - 1), i - 1), // 插入位置右侧的元素
last = matrix[i].splice(-1, 1), // 数组尾元素
first = matrix[i].splice(0, 1); // 数组首元素
// 在指定位置插入元素
arr = arr.concat(last, first, insertRight);
} if (matrix.length > 1 && i === matrix.length - 1) {
var insertRight = matrix[0].length === 1 ?
[] :
arr.splice(-(matrix.length - 2), matrix.length - 2);
// 将最后一行倒叙排列然后插入指定位置
arr = arr.concat(matrix[matrix.length - 1].reverse(), insertRight);
} }
// 删除矩阵的首尾行,得到的就是下一次需要遍历的矩阵
matrix.splice(0, 1);
matrix.splice(-1, 1); ans = ans.concat(arr);
// 根据矩阵内是否还存在数组进行递归
if (matrix.length >= 1) {
spiralLoop(matrix);
} } spiralLoop(matrix); return ans; };

以上程序的运行时间大约在 60 ms 左右,超过所有提交答案的五成,中规中矩吧,距离最优算法还有一定差距。

官方答案

LeetCode 原站给出了这道题的解题思路及代码,中文站则没有。官方介绍了两种方法,一种是模拟法,另一种是逐层法,其中逐层法的思路和我的思路是相同的,不过单层循环的方法不同。对于二维矩阵的题目,我最先想到的也是模拟法,也就是模拟行走路线及方向,但是因为判断条件有点复杂而放弃了。具体实现可以看官网文章 https://leetcode.com/articles/spiral-matrix/,以下是两种方法的 python 实现,因时间关系,我就不写 JS 版本了,后续有时间再补上,感兴趣的博友可以自己转换。

1、模拟法

class Solution(object):
def spiralOrder(self, matrix):
if not matrix: return []
R, C = len(matrix), len(matrix[0])
seen = [[False] * C for _ in matrix]
ans = []
dr = [0, 1, 0, -1]
dc = [1, 0, -1, 0]
r = c = di = 0
for _ in range(R * C):
ans.append(matrix[r][c])
seen[r][c] = True
cr, cc = r + dr[di], c + dc[di]
if 0 <= cr < R and 0 <= cc < C and not seen[cr][cc]:
r, c = cr, cc
else:
di = (di + 1) % 4
r, c = r + dr[di], c + dc[di]
return ans

2、逐层法

class Solution(object):
def spiralOrder(self, matrix):
def spiral_coords(r1, c1, r2, c2):
for c in range(c1, c2 + 1):
yield r1, c
for r in range(r1 + 1, r2 + 1):
yield r, c2
if r1 < r2 and c1 < c2:
for c in range(c2 - 1, c1, -1):
yield r2, c
for r in range(r2, r1, -1):
yield r, c1 if not matrix: return []
ans = []
r1, r2 = 0, len(matrix) - 1
c1, c2 = 0, len(matrix[0]) - 1
while r1 <= r2 and c1 <= c2:
for r, c in spiral_coords(r1, c1, r2, c2):
ans.append(matrix[r][c])
r1 += 1; r2 -= 1
c1 += 1; c2 -= 1
return ans

使用 JS 输出螺旋矩阵的更多相关文章

  1. 关于输出螺旋矩阵的demo

    输出类似 1 2 3 8 9 4 7 6 5 主要难点是如何找到表示的算法 我的理解是,先生成一个n*n的矩阵,然后再往里面塞数字,而塞的方法分别有四种:由左往右,由上往下,由右往左,由下往上,没塞完 ...

  2. PAT 1050. 螺旋矩阵(25)

    本题要求将给定的N个正整数按非递增的顺序,填入"螺旋矩阵".所谓"螺旋矩阵",是指从左上角第1个格子开始,按顺时针螺旋方向填充.要求矩阵的规模为m行n列,满足条 ...

  3. PAT-乙级-1050. 螺旋矩阵(25)

    1050. 螺旋矩阵(25) 时间限制 150 ms 内存限制 65536 kB 代码长度限制 8000 B 判题程序 Standard 作者 CHEN, Yue 本题要求将给定的N个正整数按非递增的 ...

  4. PAT 1050 螺旋矩阵(25)(代码)

    1050 螺旋矩阵(25)(25 分) 本题要求将给定的N个正整数按非递增的顺序,填入"螺旋矩阵".所谓"螺旋矩阵",是指从左上角第1个格子开始,按顺时针螺旋方 ...

  5. PAT B1050 螺旋矩阵 (25 分)

    本题要求将给定的 N 个正整数按非递增的顺序,填入“螺旋矩阵”.所谓“螺旋矩阵”,是指从左上角第 1 个格子开始,按顺时针螺旋方向填充.要求矩阵的规模为 m 行 n 列,满足条件:m×n 等于 N:m ...

  6. 1050. 螺旋矩阵(25) pat乙级题

    本题要求将给定的N个正整数按非递增的顺序,填入“螺旋矩阵”.所谓“螺旋矩阵”,是指从左上角第1个格子开始,按顺时针螺旋方向填充.要求矩阵的规模为m行n列,满足条件:m*n等于N:m>=n:且m- ...

  7. PAT——1050. 螺旋矩阵

    本题要求将给定的N个正整数按非递增的顺序,填入“螺旋矩阵”.所谓“螺旋矩阵”,是指从左上角第1个格子开始,按顺时针螺旋方向填充.要求矩阵的规模为m行n列,满足条件:m*n等于N:m>=n:且m- ...

  8. 【算法笔记】B1050 螺旋矩阵

    1050 螺旋矩阵 (25 分)   本题要求将给定的 N 个正整数按非递增的顺序,填入“螺旋矩阵”.所谓“螺旋矩阵”,是指从左上角第 1 个格子开始,按顺时针螺旋方向填充.要求矩阵的规模为 m 行  ...

  9. PAT 1050 螺旋矩阵

    https://pintia.cn/problem-sets/994805260223102976/problems/994805275146436608 本题要求将给定的 N 个正整数按非递增的顺序 ...

随机推荐

  1. 微信小程序开发之多图片上传+服务端接收

    前言: 业务需求,这次需要做一个小程序同时选中三张图片一起上传到服务端,后端使用的.NET WEBAPI接收数据保存. 使用技术: 在这章中将会使用到微信小程序wx.uploadFile(Object ...

  2. [Nuget]Nuget命令行工具安装

    下载 地址:https://www.nuget.org/downloads 直接下最新推荐版本(recommended latest)就好了. 是个单一的nuget.exe文件. 安装配置 想要在wi ...

  3. Python存储系统(Memcached)

    Memcached是一个自由开源的,高性能,分布式内存对象缓存系统. 本质上,它是一个简洁的key-value存储系统. 其主要用途有:动态数据库缓存.不同应用(语言)中共享数据 安装 安装及命令介绍 ...

  4. Appium在Android7.0及以上系统运行时报错的解决方案

    背景:在使用Samsung S系列手机进行自动化测试时,发现同样脚本的情况下华为荣耀系列可以正常运行,最终发现差异在于Android7.0及以上系统和appium版本不匹配,需要升级appium.但需 ...

  5. 使用ASP.NET Core开发GraphQL服务器 -- 预备知识(上)

    为了介绍使用ASP.NET Core构建GraphQL服务器,本文需要介绍一下GraphQL,其实看官网的文档就行. 什么是GraphQL? GraphQL 既是一种用于 API 的查询语言也是一个满 ...

  6. ACache【轻量级的开源缓存框架】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 官方介绍 ASimpleCache 是一个为android制定的 轻量级的 开源缓存框架.轻量到只有一个java文件(由十几个类精简 ...

  7. SpinnerViewPop【PopWindow样式(单选)、Dialog样式(单选+多选)的下拉菜单】

    版权声明:本文为HaiyuKing原创文章,转载请注明出处! 前言 对下拉菜单的文本区域和列表区域进行了封装.包括两种展现方式:popwindow(单选).dialog(单选+多选) 因为该封装需要在 ...

  8. Linux framebuffer测试程序

    Linux framebuffer的框架非常简单, 对于应用程序就是操作一块内存(俗称帧缓存), 当然也有可能是双缓存, 一般用于高帧率场景, 一块帧在填充数据时, 另一块在显示, 接着对调过来, 那 ...

  9. EffectiveJava阅读笔记(一)

    考虑用静态工厂方法代替构造器 一.概述 二.使用静态工厂的优势 获取类对象的两种方式: 使用公有构造方法 静态工厂方法 1.介绍 有名称 不必每次调用时创建一个新对象 可以返回原类型的任何子类型对象 ...

  10. 关于Exceptionless的使用注意

    大家都应该比较熟悉NLOG,我们知道log4net和nlog,也有其它的记日志框架.目前我们的生产环境使用nlog,而且对Exceptionless的对接也是无缝的.可能有人会问为什么不用ELK,主要 ...