【问题标题】:Spiral Matrix Algorithm螺旋矩阵算法
【发布时间】:2017-02-20 21:16:29
【问题描述】:

我无法解决以下问题中的奇数输入情况:给定一个 m x n 元素(m 行,n 列)的矩阵,以螺旋顺序返回矩阵的所有元素。

For example,
Given the following matrix:

[
 [ 1, 2, 3 ],
 [ 4, 5, 6 ],
 [ 7, 8, 9 ]
]
You should return [1,2,3,6,9,8,7,4,5].

我的代码适用于所有更大的测试用例,但对于诸如

之类的事情却失败了
[[6,9,7]]

而且我不确定如何构建我的代码来处理这些输入。有人有想法吗?

def spiral_order(matrix)
    return nil if matrix.nil? 
    return [] if matrix.empty?
    m = matrix.length - 1
    n = matrix.first.length - 1
    start_col = start_row = 0 
    end_col = n
    end_row = m
    visited = []
    iter = 0
    until start_row > end_row && start_col > end_col
        until iter > end_col
            visited << matrix[start_row][iter]
            iter+=1
        end
        start_row += 1
        iter = start_row

        until iter > end_row
            visited << matrix[iter][end_col]
            iter += 1
        end
        end_col -= 1
        iter = end_col

        until iter < start_col
            visited << matrix[end_row][iter]
            iter-=1
        end
        end_row -= 1
        iter = end_row

        until iter < start_row 
            visited << matrix[iter][start_col]
            iter -= 1
         end
         start_col += 1
         iter = start_col
    end

    visited
end

在 [6,9,7] 上,我在第 17 行收到一个 nil 错误。我知道整个循环运行了两次(这本身不应该是这种情况,因为我正在增加开始限制并减少结束限制)但我正在努力创建既适用于常规输入又适用于奇怪情况的代码,而无需投入大量条件来处理更不寻常的情况。

【问题讨论】:

  • 矩阵会一直是正方形的吗?如果是这样,我认为您可以在数组上使用枚举选项。对于以下步骤,打印该值然后删除/弹出以使其不被使用。 1) 顶行的值 2) 从索引 2 开始的每个数组中的最后一项。 3) 使用 reverse_each 的底部数组 4) 每个数组的第一项反向。
  • 你已经接近了。您需要添加检查,以便每当您将任一维度的大小减小为零(start_col == end_col,start_row == end_row)时,您都会立即从外部循环中中断。目前您的代码一直在尝试添加不应添加的元素。
  • @Gene 当 end_row == start_row 时,这意味着该最后一行之外的所有元素都已被访问。但是如果top_col和end_col之间存在差异,那这列中的元素不是还要访问吗?这就是我的想法.. 所以我没有包含那个 break 语句
  • 抱歉应该有start_col &gt; end_colstart_row &gt; end_row。例如。在您的“坏”示例中,在您访问了“顶”行(在这种情况下是唯一的行)之后,start_row 会递增,因此start_row &gt; end_row,这意味着您应该完毕。当前算法不会停止,因此它最终会尝试访问它不应该访问的元素。

标签: ruby algorithm debugging matrix


【解决方案1】:

这可以使用一组更简单的代码来解决。从矩阵中剥离第一行,旋转矩阵,重复直到为空。

def spiral_order(matrix)
  m = matrix.dup
  result = []
  until m.size < 1
    result << m.shift
    m = m.transpose.reverse
  end
  result.flatten
end

>> matrix = [[1,2,3],[4,5,6],[7,8,9]]
>> spiral_order(matrix)
=> [1, 2, 3, 6, 9, 8, 7, 4, 5]

>> matrix = [[6,9,7]]
>> spiral_order(matrix)
=> [6, 9, 7]

如果您正在处理大型矩阵并希望避免多次重复,那么您可以这样做:

def spiral_order(matrix)
  m = matrix.map(&:dup)
  result = []
  until m.size < 1
    result << m.shift
    result << m.map(&:pop)
    result << (m.pop || []).reverse
    result << m.map(&:shift).reverse
  end
  result.flatten.compact
end

该算法的工作原理如下:第 2 行对矩阵进行了深度复制,因此传入的原始矩阵保持不变。第 5 行剥去顶行。第 6 行去掉了右列。第 7 行剥去底行并将其反转。 (|| [] 确保我们不会在 nil 值上调用 #reverse。)第 8 行剥离左列并将其反转。重复第 5-8 行,直到矩阵为空。此时,第 10 行删除内部数组和 nil 并返回结果。

【讨论】:

  • 我稍作修改以避免改变传递给方法的矩阵。无论维度如何,此算法都有效,并在传递空矩阵 [[]] 时返回 []
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2022-07-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多