从外面盘旋

时间:2015-03-03 16:46:25

标签: ruby algorithm spiral

我希望循环一个类似于Looping in a spiral的矩阵,但是从外到内循环,而不是从里到外循环。任何人都可以帮助我为一个任何大小的矩阵做一个好的方法,最好是在Ruby中吗?

实施例: 在3x4矩阵中,我想从右边的[0,0]开始,然后在达到[3,0]时向下移动,在[3,2]等处向左移动。

[0,0] [1,0] [2,0] [3,0]
[0,1] [1,1] [2,1] [3,1]
[0,2] [1,2] [2,2] [3,2]

要移动的订单如下所示:

0  1  2  3
9  10 11 4
8  7  6  5

输出结果为:

[0,0], [1,0], [2,0], [3,0], [3,1], [3,2], [2,2], [1,2], [0,2], [0,1], [1,1], [2,1]

4 个答案:

答案 0 :(得分:10)

不失一般性,让我们把数组写成:

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

期望的结果是:

[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16]

我会使用帮手:

def rotate_anticlockwise(arr)
  arr.map(&:reverse).transpose
end

例如:

rotate_anticlockwise(arr)
  #=> [[4,  5,  6, 7],
  #    [3, 14, 15, 8],
  #    [2, 13, 16, 9],
  #    [1, 12, 11, 10]] 

我们现在可以按如下方式计算所需的结果:

out = []
a = arr.map(&:dup)
while a.any?
  out.concat(a.shift)
  a = rotate_anticlockwise(a)
end
out
  # => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16] 

答案 1 :(得分:5)

这个问题一直令我着迷。 @CarySwoveland的诀窍让它在Ruby中非常优雅。这是一个单行的方法:

def spiral(matrix)
  matrix.empty? ? [] : matrix.shift + spiral(matrix.transpose.reverse)
end

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

spiral(arr)

# => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]

然而,这种方法的一个缺陷是它会改变原始矩阵arr

arr

# => [[12, 13, 14, 5], [11, 16, 15, 6], [10, 9, 8, 7]]

gist中有几个答案值得一看。

答案 2 :(得分:2)

这是working C code,从外到内以顺时针方式打印2D矩阵。

int n = 2, m = 5;
    int arr[2][5] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};

    int top = 0, bottom = n-1, right = m-1, left = 0, i=0, j=0;

    printf("%d ", arr[i][j]);

    while(1){
        if(top>bottom || left>right) break;


        if(bottom==top){
            for(j=left; j<=right; j++)
                printf("%d ", arr[top][j]);
            break;
        }

        if(right==left){
            for(i=top; i<=bottom; i++)
                printf("%d ", arr[left][i]);
            break;
        }

        int first = 1;
        while(j<=right){
            if(first){
                j++;
                first = 0;
                continue;
            }

            printf("%d ", arr[i][j]);
            j++;
        }
        j--; right--;

        first = 1;
        while(i<=bottom){
            if(first){
                i++;
                first = 0;
                continue;
            }           

            printf("%d ", arr[i][j]);
            i++;
        }
        i--; bottom--;

        first = 1;
        while(j>=left){
            if(first){
                j--;
                first = 0;
                continue;
            }

            printf("%d ", arr[i][j]);
            j--;
        }
        j++; left++;

        first = 1;
        while(i>=top+1){
            if(first){
                i--;
                first = 0;
                continue;
            }

            printf("%d ", arr[i][j]);
            i--;
        }
        i++; top++;
    }

代码背后的逻辑和推理是你保持到目前为止尚未打印的矩阵的边界。所以在程序开始时,顶部边界= 0,底部= n-1,左边= 0,右边= n-1。

在外部while循环中的每次迭代中,检查由边界定义的剩余矩阵是否退化为行或列矩阵。或者,如果已经打印了矩阵的所有元素,之后它就会突然出现循环。

此外,每个内部while循环中的'first'变量会跟踪我们正在打印的值是否是该行/ col的第一个值。第一个值将不会被打印,因为它已经在它之前的循环中打印出来。

时间复杂度:O(n)
空间复杂度:O(1)

其中n是数组中元素的数量。

答案 3 :(得分:2)

这个方法做你需要的,它循环通过外螺旋然后递归调用自己循环通过内螺旋

def inward_spiral(height, width, current_height, current_width)
  if height <= 0 || width <= 0
    return
  end

  # Right
  (width-1).times do
      puts "[#{current_width}, #{current_height}]"
      current_width += 1 
  end

  # Down
  (height-1).times do
    puts "[#{current_width}, #{current_height}]"
    current_height += 1
  end

  # Left
  if height > 1
      (width-1).times do 
          puts "[#{current_width}, #{current_height}]"
          current_width -= 1 
      end
  end

  # Up
  if width > 1
      (height-2).times do
          puts "[#{current_width}, #{current_height}]"
          current_height -= 1
      end
  end

  puts "[#{current_width}, #{current_height}]"
  inward_spiral(height-2, width-2, current_width + 1, current_height)
end

然后将其称为inward_spiral(3,4,0,0)

你也可以填充一个矩阵来绘制螺旋线,如果在每一步你用你想要得到的方向填充它:

→  →  →  →  ↴ 
↱  →  →  ↴  ↓ 
↑  ↱  ↴  ↓  ↓ 
↑  ↑  ↓  ↓  ↓ 
↑  ↑  ↓  ↓  ↓ 
↑  ↑  ↓  ↓  ↓ 
↑  ↑  ↓  ↓  ↓ 
↑  ↑  ✓  ↓  ↓ 
↑  ↑  ←  ⤶  ↓ 
↑  ←  ←  ←  ⤶