给定m×n个元素的矩阵(m行,n列),按螺旋顺序返回矩阵的所有元素。例如,给定以下矩阵: [ 1,2,3, following 4、5、6, following 7、8、9 ],您应该返回1,2,3,6,9,8,7,4 5。
的介绍
这是Leetcode.com上的中级算法。从2017年3月到2018年1月,我已经练习了十次。我在模拟访谈中写了五次算法,还观察了五位同行对算法的研究。我经历了四次在while循环中编写for循环的痛苦,我用错误编写了代码,打印了两次一行矩阵,在最后一行和第一列上复制了输出。而且,我也曾看过几次这位同行与这么多bug作斗争。总的来说,这是一个有很多乐趣的算法。
2018年1月23日,我第一次在另一个模拟采访平台上进行了一次模拟面试,而且是匿名的。
面试官问我能否只使用一个循环而不是一个write循环中的4个循环来编写解决方案,而两个循环可以在行上或下行迭代,两个用于循环在最后一列或第一列上迭代。
在模拟面试中,我已经对算法进行了十多次的研究,但我从来没有根据有限的时间关注和循环的but提出完整的想法。我的同龄人中没有一个提出了类似的想法,我以前只和一个同龄人讨论过。作为一名面试官或应聘者,我确实考虑过四种循环也是有问题的。
有一次,我在模拟面试中向同行抱怨,当时我正在研究这个螺旋矩阵问题的四个for循环。我告诉同行,我喜欢使用额外的数组来标记访问,这样我的四个for循环总是可以从0转到行- 1或0到cols -1。代码将需要额外的时间来迭代已访问的元素,但是绝对不必担心定义开始和结束位置。同行的建议是不要成为模拟面试中的黑客,你应该始终听从面试官的暗示或建议。那只是我非常接近这个新想法的时候。
通过代码博客回顾所有过去的实践是很有帮助的。这里是关于螺旋矩阵算法实践的博客之一。
算法的
我编写了一个C#解决方案,并使用额外的空间声明一个数组来标记是否访问了矩阵中的元素。若要更改方向,请执行以下操作:如果当前行和列超出了矩阵的边界,或以前访问过它。我在模拟面试之后写了这个解决方案,我不敢相信在经过这么多练习之后,在模拟面试中我需要这么多提示,一个提示代表四个方向,一个提示使用额外数组访问数组。
这是C#解决方案。
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace MatrixSpiralPrint
{
class Program
{
/// <summary>
/// Leetcode Spiral Matrix
/// https://leetcode.com/problems/spiral-matrix/description/
/// </summary>
/// <param name="args"></param>
static void Main(string[] args)
{
var spiral = MatrixSpiralPrint(new int[,] { { 1, 2, 3 }, { 8, 9, 4 }, { 7, 6, 5 } });
Debug.Assert(String.Join(",", spiral).CompareTo("123456789") == 0);
}
/// <summary>
/// Navigate the direction automatically by checking boudary and checking
/// the status of element visited status.
/// Only one loop, perfect idea to fit in mock interview or interview
/// 20 minutes setting
/// </summary>
/// <param name="array"></param>
/// <returns></returns>
public static int[] MatrixSpiralPrint(int[,] array)
{
if (array == null || array.GetLength(0) == 0 || array.GetLength(1) == 0)
{
return new int[0];
}
int rows = array.GetLength(0);
int columns = array.GetLength(1);
var visited = new int[rows, columns];
int index = 0;
int totalNumbers = rows * columns;
var fourDirections = new List<int[]>();
fourDirections.Add(new int[] { 0, 1 }); // left to right - top row
fourDirections.Add(new int[] { 1, 0 }); // top to down - last column
fourDirections.Add(new int[] { 0, -1 }); // right to left - bottom row
fourDirections.Add(new int[] { -1, 0 }); // bottom up - first row
int direction = 0;
int row = 0;
int col = 0;
var spiral = new int[totalNumbers];
while (index < totalNumbers)
{
var current = array[row, col];
spiral[index++] = current;
visited[row, col] = 1; // mark visit
var nextRow = row + fourDirections[direction][0];
var nextCol = col + fourDirections[direction][1];
var isOutArrayBoundary = nextRow < 0 || nextRow >= rows || nextCol < 0 || nextCol >= columns;
if (isOutArrayBoundary || visited[nextRow, nextCol] == 1) // change the direction
{
direction = (direction + 1) % 4; // map to 0 to 3
}
row += fourDirections[direction][0];
col += fourDirections[direction][1];
}
return spiral;
}
}
}
发布于 2018-01-30 21:08:41
visited
中的值要么为0,要么为1。为此,boolean
矩阵将是一种自然的选择。
使用visited
数组使实现更加简单。另一种方法是,如果没有额外的存储,就需要跟踪当前方向上要执行的步骤的数量。考虑正确的值并观察模式:
columns
rows - 1
columns - 1
rows - 2
columns - 2
rows - 3
columns - 3
rows - 4
基本上,交替列数和行数,每个方向变化减少1。当下一个步骤数为0时,就该停止了。编写起来要复杂一些,但要使用常量的额外存储。
0行或0列的情况不需要特殊处理。结果数组将被创建为空,主循环将不执行任何步骤。
null
值用于array
的情况是非意义输入。如果这种情况发生,它看上去就像是来电者的故障。最好是通过抛出一个显式异常来表示存在问题。
fourDirections
包含4个方向。不要按集合的大小命名集合。只要directions
就好了。
https://codereview.stackexchange.com/questions/185935
复制相似问题