以螺旋顺序打印矩阵

时间:2017-10-11 20:15:39

标签: arrays ruby algorithm multidimensional-array

我正在尝试以螺旋顺序(顺时针方向)打印数组,但我的代码无法正确打印。

我的数组是:

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

任何人都可以帮我理解我的代码有什么问题吗?

3 个答案:

答案 0 :(得分:2)

代码中的错误位于r..lb..t,其中r大于lb大于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

答案 1 :(得分:0)

您应该在减少循环中使用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)

答案 2 :(得分:0)

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

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循环替换
  • 打印从方法中提取的值,而不是产生值(调用者决定如何处理它)

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

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