Ruby中的矩阵环旋转

时间:2015-09-19 04:07:32

标签: ruby algorithm matrix graph

这是一个黑客等级问题(https://www.hackerrank.com/challenges/matrix-rotation-algo),需要将矩阵旋转R次。 矩阵是MxN

我提出的解决方案旋转每个环(外部 - >内部)。然而,这是非常低效的,并没有通过测试。

#!/usr/bin/ruby
def print_matrix(matrix)
    matrix.each do |a|
        a.each do |n|
            print "#{n} "
        end
        puts 
    end
    puts
end

def rotate_ring(matrix,s_i,s_j,m,n)
    rotated = matrix.inject([]) { |a,element| a << element.dup }
    for i in (s_i...m)
        for j in (s_j...n)
            case [i,j]
                # Move items on corners
                #Top Left Corner
                when [s_i,s_j]
                    rotated[i+1][j] = matrix[i][j]
                #Bottom Left Corner
                when [m-1,s_j]
                    rotated[i][j+1] = matrix[i][j]
                #Bottom Right Corner
                when [m-1,n-1]
                    rotated[i-1][j] = matrix[i][j]
                #Top Right Corner
                when [s_i,n-1]
                    rotated[i][j-1] = matrix[i][j]
                ##################  
                # Move other items
                # Top Row
                when proc{|i,j| i == s_i and j>0 }
                    rotated[i][j-1] = matrix[i][j]
                # Bottom Row
                when proc{|i,j| i == m-1}
                    rotated[i][j+1] = matrix[i][j]
                # Left Column
                when proc{|i,j| i >= 0 and j == s_j}
                    rotated[i+1][j] = matrix[i][j]
                # Right Column
                when proc{|i,j| i >= 0 and j == n-1}
                rotated[i-1][j] = matrix[i][j]
            end
        end
    end
    return rotated
end

def rotate_matrix(matrix,m,n,r)
    s_i = 0
    s_j = 0
    min = ([m,n].min)/2
    r.times do
        for t in 0...min
            matrix = rotate_ring(matrix,0+t,0+t,m-t,n-t)
        end
    end
    return matrix
end

matrix = [['a','b','c','d'],
          ['e','f','g','h'],
          ['i','j','k','l'],
          ['m','n','o','p'],    
          ['q','r','s','t']]

m = matrix.size
n = matrix[0].size

print_matrix(matrix)
print_matrix(rotate_matrix(matrix,m,n,1))

1 个答案:

答案 0 :(得分:2)

<强>代码

def rotate_rings(arr, n)
  m = arr.transpose.transpose
  n.times { rotate_rings_once(m) }
  m
end

def rotate_rings_once(arr)
  nrings = (arr.size/2)
  m = arr.transpose.transpose
  4.times do
    nrings.times { |i| arr[i][i..-i-1] = m[i][i+1..-i-1] << m[i+1][-i-1] }
    rotate_array!(arr)
    rotate_array!(m)
  end
end

def rotate_array!(arr)
  arr.replace(arr.map!(&:reverse).transpose)
end

<强>实施例

arr = [['a','b','c','d'],
       ['e','f','g','h'],
       ['i','j','k','l'],
       ['m','n','o','p'],    
       ['q','r','s','t']]

rotate_rings(arr, 0)
  #=> [["a", "b", "c", "d"],
  #    ["e", "f", "g", "h"],
  #    ["i", "j", "k", "l"],
  #    ["m", "n", "o", "p"],
  #    ["q", "r", "s", "t"]] 
rotate_rings(arr, 1)
  #=> [["b", "c", "d", "h"],
  #    ["a", "g", "k", "l"],
  #    ["e", "f", "o", "p"],
  #    ["i", "j", "n", "t"],
  #    ["m", "q", "r", "s"]] 
rotate_rings(arr, 2)
  #=> [["c", "d", "h", "l"],
  #    ["b", "k", "o", "p"],
  #    ["a", "g", "n", "t"],
  #    ["e", "f", "j", "s"],
  #    ["i", "m", "q", "r"]] 

arr = [[ 1,  2,  3,  4,  5],
       [ 6,  7,  8,  9, 10],
       [11, 12, 13, 14, 15],
       [16, 17, 18, 19, 20]]

rotate_rings(arr, 0)
  #=> [[ 1,  2,  3,  4,  5],
  #    [ 6,  7,  8,  9, 10],
  #    [11, 12, 13, 14, 15],
  #    [16, 17, 18, 19, 20]] 
rotate_rings(arr, 1)
  #=> [[ 2,  3,  4,  5, 10],
  #    [ 1,  8,  9, 14, 15],
  #    [ 6,  7, 12, 13, 20],
  #    [11, 16, 17, 18, 19]]
rotate_rings(arr, 2)
  #=> [[ 3,  4,  5, 10, 15],
  #    [ 2,  9, 14, 13, 20],
  #    [ 1,  8,  7, 12, 19],
  #    [ 6, 11, 16, 17, 18]]

备注:

  1. rotate_array!是辅助方法,可以逆时针旋转其参数(数组)。例如:

    m = [[10, 11, 12, 13],
         [14, 15, 16, 17],
         [18, 19, 20, 21],
         [22, 23, 24, 25],
         [26, 27, 28, 20]] 
    
    rotate_array!(m)
      #=> [[13, 17, 21, 25, 20],
      #    [12, 16, 20, 24, 28],
      #    [11, 15, 19, 23, 27],
      #    [10, 14, 18, 22, 26]]` 
    
  2. rotate_array!的返回值也是其参数m的新值。如果我们轮换4次,我们将返回原始数组。

    1. 目的:

      m = arr.transpose.transpose
      
    2. 是制作arr的深层副本,以便后者不会发生变异。我也可以使用:

          m = arr.dup.map(:&dup)
      
      1. rotate_rings_once(arr)

        nrings = (arr.size/2)
        
      2. 是数组中的环数。圈ii = 0, 1,..., nrings-1))的左上角元素是arr[i][i]。对于每个环i,环的顶行使用表达式计算:

            arr[i][i..-i-1] = m[i][i+1..-i-1] << m[i+1][-i-1]
        

        其中m是在arr元素移位之前计算的arr的深层副本。

        然后旋转数组arrm,并移动arr中每个环的(新)顶行的元素。这些计算重复了三次。