首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >Leetcode 54:螺旋矩阵

Leetcode 54:螺旋矩阵
EN

Code Review用户
提问于 2018-01-25 05:37:41
回答 1查看 1.1K关注 0票数 7

问题陈述

给定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作斗争。总的来说,这是一个有很多乐趣的算法。

如何在模拟面试中编写无bug的解决方案?

2018年1月23日,我第一次在另一个模拟采访平台上进行了一次模拟面试,而且是匿名的。

面试官问我能否只使用一个循环而不是一个write循环中的4个循环来编写解决方案,而两个循环可以在行上或下行迭代,两个用于循环在最后一列或第一列上迭代。

在模拟面试中,我已经对算法进行了十多次的研究,但我从来没有根据有限的时间关注和循环的but提出完整的想法。我的同龄人中没有一个提出了类似的想法,我以前只和一个同龄人讨论过。作为一名面试官或应聘者,我确实考虑过四种循环也是有问题的。

有一次,我在模拟面试中向同行抱怨,当时我正在研究这个螺旋矩阵问题的四个for循环。我告诉同行,我喜欢使用额外的数组来标记访问,这样我的四个for循环总是可以从0转到行- 1或0到cols -1。代码将需要额外的时间来迭代已访问的元素,但是绝对不必担心定义开始和结束位置。同行的建议是不要成为模拟面试中的黑客,你应该始终听从面试官的暗示或建议。那只是我非常接近这个新想法的时候。

通过代码博客回顾所有过去的实践是很有帮助的。这里是关于螺旋矩阵算法实践的博客之一。

算法的

分析我喜欢做的一件事是在模拟面试中编写任何代码之前,先对算法进行一些分析。对我来说,仔细研究各种想法,找出最优的想法,也是很有帮助的。 当我在这个网站上问一个问题的时候,我也喜欢练习这个方法。 下面是螺旋矩阵算法的几个关键词。 方向-有四个方向。如果需要,按顺时针方向改变方向,从左上角开始(0,0)。 范围-待在数组内 访问-只访问数组中的每个元素一次。请勿访问超过一次。 顺序-按照顺时针方向的顺序,从(0,0)开始。 具有可读代码的

快速解决方案

我编写了一个C#解决方案,并使用额外的空间声明一个数组来标记是否访问了矩阵中的元素。若要更改方向,请执行以下操作:如果当前行和列超出了矩阵的边界,或以前访问过它。我在模拟面试之后写了这个解决方案,我不敢相信在经过这么多练习之后,在模拟面试中我需要这么多提示,一个提示代表四个方向,一个提示使用额外数组访问数组。

这是C#解决方案。

代码语言:javascript
运行
复制
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;
        }
    }
}
EN

回答 1

Code Review用户

回答已采纳

发布于 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就好了。

票数 3
EN
页面原文内容由Code Review提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://codereview.stackexchange.com/questions/185935

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档