【问题标题】:Printing Matrix in Spiral Order以螺旋顺序打印矩阵
【发布时间】:2018-03-23 15:14:22
【问题描述】:

我正在尝试以螺旋顺序(顺时针)打印一个数组,但我的代码没有正确打印。

我的数组是:

a = [
      [2,  4,  6,  8],
      [5,  9, 12, 16],
      [2, 11,  5,  9],
      [3,  2,  1,  8]
    ]

我的解决方案:

def print_circ(arr, row, col)
  t = 0
  b = row - 1
  l = 0
  r = col - 1
  dir = 0
  while t <= b and l <= r do
    if dir == 0
      for i in l..r
        puts arr[t][i]
      end
      t += 1
    end
    if dir == 1
      for i in t..b
        puts arr[i][r]
      end
      r -= 1
    end
    if dir == 2
      for i in r..l
        puts arr[b][i]
      end
      b -= 1
    end
    if dir == 3
      for i in b..t
        puts arr[i][l]
      end
      l += 1
    end
    dir = (dir+1)%4
  end
end

当我运行它时,它不会打印出底部或左侧边缘:

2
4
6
8
16
9
8
9
12
5
11

谁能帮我理解我的代码有什么问题?

【问题讨论】:

  • 在 Ruby 中,您应该避免使用 C 或 Java 风格的 for 循环,使用迭代器,这样您就不必担心数组限制了。我添加了一个更 Rubyesque 的解决方案。

标签: arrays ruby algorithm multidimensional-array


【解决方案1】:

代码中的错误位于r..lb..t,其中r 大于l,而b 大于t。当您定义从较高整数到较低整数的范围时,该范围实际上是空的。例如:

irb> (0..3).to_a
 => [0, 1, 2, 3]
irb> (3..0).to_a
 => []

要修复反向迭代代码,您可以将 for i in r..l 循环更改为 (l..r).reverse_each do |i| ... end

【讨论】:

  • 感谢您对 Ruby 中范围的澄清!
  • 您的解释是正确的,但建议的解决方案不起作用:(3..0).reverse_each.to_a 也是空的。这是因为reverse_each 基于each(已经为空)构建了一个临时数组,然后以相反的顺序迭代该(空)数组。
  • @Stefan 这就是为什么我没有提议(3..0).reverse_each。在这种情况下,我提出了(0..3).reverse_each,与l = 0r = 3。 :)
  • @HengXiong 你的权利,我忽略了你把r..l 改成了l..r
【解决方案2】:

您应该在递减循环中使用downto

这里是你的代码修复:

def print_circ(arr, row, col)
  t = 0
  b = row - 1
  l = 0
  r = col - 1
  dir = 0

  while t <= b and l <= r do

    if dir == 0
      for i in l..r
        puts arr[t][i]
      end
      t += 1
    end

    if dir == 1
      for i in t..b
        puts arr[i][r]
      end
      r -= 1
    end

    if dir == 2
      for i in r.downto(l)
        puts arr[b][i]
      end
      b -= 1
    end

    if dir == 3
      for i in b.downto(t)
        puts arr[i][l]
      end
      l += 1
    end

    dir = (dir+1)%4

  end

end

print_circ([[2,4,6,8],[5,9,12,16],[2,11,5,9],[3,2,1,8]], 4, 4)

【讨论】:

  • 我不确定谁先在这里回答,因为我编辑了代码,因为没有对齐。哦,好吧...
  • 感谢您提供有关downto 的信息! @heng 使用了 reverse_each 方法,但我只是想知道您是否也可以在 .each do 循环中实现 downto ?如果是这样,你介意分享一个例子吗?
  • for i in r.downto(l) - fordownto 的组合在我看来很奇怪。由于downto 已经提供了迭代,你应该简单地使用r.downto(l) do |i|
【解决方案3】:

您的代码问题已经解决。我只是想提供一个更惯用的代码版本:

def each_spiral_value(arr)
  t = 0
  b = arr.size - 1
  l = 0
  r = arr.first.size - 1
  dir = [:right, :down, :left, :up].cycle

  while t <= b && l <= r
    case dir.next
    when :right
      l.upto(r) { |i| yield arr[t][i] }
      t += 1
    when :down
      t.upto(b) { |i| yield arr[i][r] }
      r -= 1
    when :left
      r.downto(l) { |i| yield arr[b][i] }
      b -= 1
    when :up
      b.downto(t) { |i| yield arr[i][l] }
      l += 1
    end
  end
end

each_spiral_value(a) { |v| puts v }

变化:

  • br 不是显式传递,而是分别根据数组的 size 及其 first 元素的大小计算得出
  • 方向值已从数字更改为符号
  • dir 使用 cycle 创建一个通过调用 next 循环的枚举器
  • 使用case 语句代替多个if 语句
  • for 循环被 uptodownto 循环替换
  • 打印值是从方法中提取的,而是生成值(调用者决定如何处理它)

您也可以将块传递给cycle,而不是手动调用next。这将有效地替换您的 while 循环:

[:right, :down, :left, :up].cycle do |dir|
  break if t > b || l > r
  case dir
    # ...
  end
end

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-01
    • 1970-01-01
    相关资源
    最近更新 更多