这个 O(n) 矩阵旋转算法可以就地完成并保持 O(n) 吗?

Can this O(n) Matrix Rotation algorithm be done in place and remain O(n)?

问题:

是否可以将下面发布的算法调整为使用相同的数组(表示二维矩阵)进行顺时针旋转而不是使用第二个数组并仍然保持 O(n) 复杂度?

代码:

import java.util.Random;

public class MatrixRotation {

  public static void main(String[] args) {
    int dimension = 5;

    int[] array = generate(dimension);
    print(array, dimension);

    int[] clockwise = clockwise(array, dimension);
    print(clockwise, dimension);
  }

  //Generate a matrix with random values
  private static int[] generate(int dimension) {
    Random rand = new Random();
    int[] array = new int[dimension * dimension];
    for(int i = 0; i < array.length; i++) {
      array[i] = rand.nextInt(10);
    }
    return array;
  }

  //Rotates the matrix clockwise by calculating where the value's position should be after the rotation
  private static int[] clockwise(int[] array, int dimension) {
    int[] rotated = new int[array.length];
    int baseCount = dimension;

    for(int i = 0; i < array.length; i++) {
      int remainder = i % dimension;

      if(remainder == 0)
        baseCount--;

      int position = baseCount + (dimension * remainder);

      //I suspect I can do some kinda swapping functionality here but am stumped

      rotated[position] = array[i];
    }

    return rotated;
  }

  //Used to display the matrix
  private static void print(int[] array, int dimension) {
    for(int i = 0; i < array.length; i++) {
      if(i % dimension == 0) 
        System.out.println();
      System.out.print(array[i] + " ");
    }
    System.out.println();
  }
}

示例输出:

1 7 4 1 4 
2 3 5 2 9 
4 3 9 3 1 
5 8 7 5 6 
3 3 7 2 5 

3 5 4 2 1 
3 8 3 3 7 
7 7 9 5 4 
2 5 3 2 1 
5 6 1 9 4 

背景:

前几天我正在阅读一个关于一维数组中表示的矩阵旋转的问题,并决定尝试一下。我设法通过计算旋转后值的下一个位置成功地创建了一个旋转算法。目前我正在尝试确定是否有办法将它保持为 O(n),同时通过将它保持在同一个数组中来减少使用的 space。关于如何实现这一点有什么想法吗?

我找到了可行的解决方案!我无法确定如何使它与发布的算法一起工作,但是一旦我从头开始设计它并从头开始进行旋转交换,我就找到了一个具有相同复杂性(本质上)的解决方案。我设计它的想法是通过 "onion layers" 从外到内工作,找到每一层的角,然后旋转它们以及它们的相对方向相邻。类似于:

    ↓                      ↓                     ↓
    5 5 8 2 1 ←          7 5 8 2 5           7 2 8 2 5  
    9 4 8 2 3            9 4 8 2 3 ←         9 4 8 2 5 
    6 3 7 5 4            6 3 7 5 4         → 6 3 7 5 4 ←       Ect...
    2 6 4 2 7          → 2 6 4 2 7           5 6 4 2 7 
  → 7 0 7 5 5            5 0 7 5 1           5 0 7 3 1 
            ↑                  ↑                 ↑

对于每一层。

代码:

  private static int[] clockwise2(int[] array, int dimension) {
    int layers = dimension / 2; //Total layers of the onion
    //Loop through the layers
    for (int i = 0; i < layers; i++) {
      int layerWidth = dimension - 2 * i; //Current layer width

      int topStart = i + dimension * i; //Top left corner
      int rightStart = topStart + (layerWidth - 1); //Top right corner
      int bottomStart = (array.length - 1) - topStart; //Bottom right corner
      int leftStart = bottomStart - (layerWidth - 1); //Bottom left corner

      //Loop values in current layer
      for (int j = 0; j < layerWidth - 1; j++) {
        int topIndex = topStart + j; //Move right
        int rightIndex = rightStart + dimension * j; //Move down
        int bottomIndex = bottomStart - j; //Move left
        int leftIndex = leftStart - dimension * j; //Move up

        //Swap the values in a circular direction
        int temp = array[topIndex];
        array[topIndex] = array[leftIndex];
        array[leftIndex] = array[bottomIndex];
        array[bottomIndex] = array[rightIndex];
        array[rightIndex] = temp;
      }
    }

    return array;
  }