Como você gira uma matriz bidimensional?


302

Inspirado no post de Raymond Chen , diga que você tem uma matriz bidimensional 4x4, escreva uma função que a gire 90 graus. Raymond vincula-se a uma solução em pseudo-código, mas eu gostaria de ver algumas coisas do mundo real.

[1][2][3][4]
[5][6][7][8]
[9][0][1][2]
[3][4][5][6]

Torna-se:

[3][9][5][1]
[4][0][6][2]
[5][1][7][3]
[6][2][8][4]

Atualização : a resposta de Nick é a mais direta, mas existe uma maneira de fazer isso melhor que n ^ 2? E se a matriz fosse 10000x10000?


99
Como você poderia fugir com menos de n ^ 2? Todos os elementos devem ser lidas e set, e há n ^ 2 elementos
erikkallen


9
Qual seu Número? Você não diz se a matriz 2D é quadrada (não é o caso geral! Por exemplo, um vetor é uma matriz com uma dimensão de 1), mas parece implicar que n é a largura e a altura e, portanto, possui n ² elementos . Faria mais sentido ter n o número de elementos, com n = w × h.
NiXar

1
Aqui está uma maneira rápida de fazer isso: armazene os índices de linha e coluna (digamos i e j). A transposição leva tempo constante (basta trocar os índices :). Você pode fazer o mesmo com as rotações (reproduzir com índices).
Saadtaame # 7/13

4
Caso n ^ 2 não seja viável. Você pode criar uma interface que acesse cada elemento. Em seguida (i, j), aplique a rotação para (i, j) acessar o elemento girado e retornar. Pode não ser o melhor soln, mas funciona.
Confunda

Respostas:


140

Aqui está em c #

int[,] array = new int[4,4] {
    { 1,2,3,4 },
    { 5,6,7,8 },
    { 9,0,1,2 },
    { 3,4,5,6 }
};

int[,] rotated = RotateMatrix(array, 4);

static int[,] RotateMatrix(int[,] matrix, int n) {
    int[,] ret = new int[n, n];

    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            ret[i, j] = matrix[n - j - 1, i];
        }
    }

    return ret;
}

6
Claro, mas e uma solução usando memória O (1)?
AlexeyMK

20
Sua solução possui complexidade de espaço O (n ^ 2). Necessidade de fazer melhor
Kshitij Jain

6
Que tal para a matriz NXM?
Rohit

18
A complexidade é linear no número de elementos na matriz. Se N é o número de elementos, a complexidade é O (N). Se N é o comprimento do lado, então sim, a complexidade é O (N ^ 2), mas isso ainda é ideal. Você precisa ler todos os elementos pelo menos uma vez. Imprimir a matriz é o mesmo complexitiy
Alejandro

6
Para uma rotação de -90 graus:ret[i][j] = matrix[j][n - i - 1]
Duncan Luk

387

Algoritmo O (n ^ 2) e O (1) espaço (sem nenhuma solução alternativa e coisas enlouquecedoras!)

Gire em +90:

  1. Transpor
  2. Inverta cada linha

Gire em -90:

Método 1 :

  1. Transpor
  2. Inverta cada coluna

Método 2:

  1. Inverta cada linha
  2. Transpor

Gire em +180:

Método 1 : girar +90 duas vezes

Método 2 : reverter cada linha e, em seguida, reverter cada coluna (transpor)

Gire -180:

Método 1 : Gire -90 duas vezes

Método 2 : reverter cada coluna e, em seguida, reverter cada linha

Método 3 : Gire em +180, pois são iguais


4
Isso foi muito útil para mim; Consegui escrever um algoritmo depois de conhecer a "[versão do pseudo-] código" desta operação. Obrigado!
Duma

13
Uma das minhas respostas favoritas de todos os tempos. Muito instrutivo!
precisa saber é o seguinte

2
Aqui está uma implementação JSFiddle para JavaScript, se alguém estiver interessado.
Mr. Polywhirl

6
Gire em -90: (1) Inverta cada linha; (2) Transpor. Haskell: rotateCW = map reverse . transposeerotateCCW = transpose . map reverse
Thomas Eding

5
Qual é a diferença entre girar 180 e -180?
Qian Chen

178

Eu gostaria de adicionar um pouco mais de detalhes. Nesta resposta, conceitos-chave são repetidos, o ritmo é lento e intencionalmente repetitivo. A solução fornecida aqui não é a mais sintaticamente compacta; é, no entanto, destinada a quem deseja aprender o que é a rotação da matriz e a implementação resultante.

Em primeiro lugar, o que é uma matriz? Para os fins desta resposta, uma matriz é apenas uma grade em que a largura e a altura são iguais. Observe que a largura e a altura de uma matriz podem ser diferentes, mas, para simplificar, este tutorial considera apenas matrizes com largura e altura iguais ( matrizes quadradas ). E sim, matrizes é o plural de matriz.

As matrizes de exemplo são: 2 × 2, 3 × 3 ou 5 × 5. Ou, mais geralmente, N × N. Uma matriz 2 × 2 terá 4 quadrados porque 2 × 2 = 4. Uma matriz 5 × 5 terá 25 quadrados porque 5 × 5 = 25. Cada quadrado é chamado de elemento ou entrada. Representaremos cada elemento com um ponto (. ) nos diagramas abaixo:

Matriz 2 × 2

. .
. .

Matriz 3 × 3

. . .
. . .
. . .

Matriz 4 × 4

. . . .
. . . .
. . . .
. . . .

Então, o que significa girar uma matriz? Vamos pegar uma matriz 2 × 2 e colocar alguns números em cada elemento para que a rotação possa ser observada:

0 1
2 3

Girar isso em 90 graus nos dá:

2 0
3 1

Nós literalmente giramos a matriz toda uma vez para a direita, assim como girar o volante de um carro. Pode ajudar a "inclinar" a matriz para o lado direito. Queremos escrever uma função, em Python, que pega uma matriz e gira uma vez para a direita. A assinatura da função será:

def rotate(matrix):
    # Algorithm goes here.

A matriz será definida usando uma matriz bidimensional:

matrix = [
    [0,1],
    [2,3]
]

Portanto, a primeira posição do índice acessa a linha. A segunda posição do índice acessa a coluna:

matrix[row][column]

Definiremos uma função utilitária para imprimir uma matriz.

def print_matrix(matrix):
    for row in matrix:
        print row

Um método de girar uma matriz é fazer uma camada de cada vez. Mas o que é uma camada? Pense em uma cebola. Assim como as camadas de uma cebola, à medida que cada camada é removida, avançamos em direção ao centro. Outras analogias são uma boneca matryoshka ou um jogo de empacotar.

A largura e a altura de uma matriz determinam o número de camadas nessa matriz. Vamos usar símbolos diferentes para cada camada:

Uma matriz 2 × 2 possui 1 camada

. .
. .

Uma matriz 3 × 3 possui 2 camadas

. . .
. x .
. . .

Uma matriz 4 × 4 tem 2 camadas

. . . .
. x x .
. x x .
. . . .

Uma matriz 5 × 5 possui 3 camadas

. . . . .
. x x x .
. x O x .
. x x x .
. . . . .

Uma matriz 6 × 6 tem 3 camadas

. . . . . .
. x x x x .
. x O O x .
. x O O x .
. x x x x .
. . . . . .

Uma matriz 7 × 7 tem 4 camadas

. . . . . . .
. x x x x x .
. x O O O x .
. x O - O x .
. x O O O x .
. x x x x x .
. . . . . . .

Você pode perceber que incrementar a largura e a altura de uma matriz em uma unidade nem sempre aumenta o número de camadas. Tomando as matrizes acima e tabulando as camadas e dimensões, vemos o número de camadas aumentar uma vez a cada dois incrementos de largura e altura:

+-----+--------+
| N×N | Layers |
+-----+--------+
| 1×1 |      1 |
| 2×2 |      1 |
| 3×3 |      2 |
| 4×4 |      2 |
| 5×5 |      3 |
| 6×6 |      3 |
| 7×7 |      4 |
+-----+--------+

No entanto, nem todas as camadas precisam ser rotacionadas. Uma matriz 1 × 1 é a mesma antes e depois da rotação. A camada 1 × 1 central é sempre a mesma antes e depois da rotação, independentemente do tamanho da matriz geral:

+-----+--------+------------------+
| N×N | Layers | Rotatable Layers |
+-----+--------+------------------+
| 1×1 |      1 |                0 |
| 2×2 |      1 |                1 |
| 3×3 |      2 |                1 |
| 4×4 |      2 |                2 |
| 5×5 |      3 |                2 |
| 6×6 |      3 |                3 |
| 7×7 |      4 |                3 |
+-----+--------+------------------+

Dada a matriz N × N, como podemos determinar programaticamente o número de camadas que precisamos rotacionar? Se dividirmos a largura ou a altura por dois e ignorarmos o restante, obteremos os seguintes resultados.

+-----+--------+------------------+---------+
| N×N | Layers | Rotatable Layers |   N/2   |
+-----+--------+------------------+---------+
| 1×1 |      1 |                0 | 1/2 = 0 |
| 2×2 |      1 |                1 | 2/2 = 1 |
| 3×3 |      2 |                1 | 3/2 = 1 |
| 4×4 |      2 |                2 | 4/2 = 2 |
| 5×5 |      3 |                2 | 5/2 = 2 |
| 6×6 |      3 |                3 | 6/2 = 3 |
| 7×7 |      4 |                3 | 7/2 = 3 |
+-----+--------+------------------+---------+

Note como N/2 corresponde ao número de camadas que precisam ser giradas? Às vezes, o número de camadas rotativas é um a menos o número total de camadas na matriz. Isso ocorre quando a camada mais interna é formada por apenas um elemento (ou seja, uma matriz 1 × 1) e, portanto, não precisa ser girada. Simplesmente é ignorado.

Indubitavelmente, precisaremos dessas informações em nossa função para girar uma matriz, então vamos adicioná-las agora:

def rotate(matrix):
    size = len(matrix)
    # Rotatable layers only.
    layer_count = size / 2

Agora sabemos o que são camadas e como determinar o número de camadas que realmente precisam ser rotacionadas. Como isolamos uma única camada para podermos rotacioná-la? Primeiro, inspecionamos uma matriz da camada mais externa, para dentro, até a camada mais interna. Uma matriz 5 × 5 possui três camadas no total e duas camadas que precisam ser rotacionadas:

. . . . .
. x x x .
. x O x .
. x x x .
. . . . .

Vejamos as colunas primeiro. A posição das colunas que definem a camada mais externa, assumindo que contamos de 0, são 0 e 4:

+--------+-----------+
| Column | 0 1 2 3 4 |
+--------+-----------+
|        | . . . . . |
|        | . x x x . |
|        | . x O x . |
|        | . x x x . |
|        | . . . . . |
+--------+-----------+

0 e 4 também são as posições das linhas da camada mais externa.

+-----+-----------+
| Row |           |
+-----+-----------+
|   0 | . . . . . |
|   1 | . x x x . |
|   2 | . x O x . |
|   3 | . x x x . |
|   4 | . . . . . |
+-----+-----------+

Esse sempre será o caso, pois a largura e a altura são as mesmas. Portanto, podemos definir as posições da coluna e da linha de uma camada com apenas dois valores (em vez de quatro).

Indo para a segunda camada, a posição das colunas é 1 e 3. E, sim, você adivinhou, é o mesmo para as linhas. É importante entender que tivemos que incrementar e diminuir as posições de linha e coluna ao mover para dentro para a próxima camada.

+-----------+---------+---------+---------+
|   Layer   |  Rows   | Columns | Rotate? |
+-----------+---------+---------+---------+
| Outermost | 0 and 4 | 0 and 4 | Yes     |
| Inner     | 1 and 3 | 1 and 3 | Yes     |
| Innermost | 2       | 2       | No      |
+-----------+---------+---------+---------+

Portanto, para inspecionar cada camada, queremos um loop com contadores crescentes e decrescentes que representem o movimento para dentro, a partir da camada mais externa. Vamos chamar isso de nosso 'loop de camada'.

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2

    for layer in range(0, layer_count):
        first = layer
        last = size - first - 1
        print 'Layer %d: first: %d, last: %d' % (layer, first, last)

# 5x5 matrix
matrix = [
    [ 0, 1, 2, 3, 4],
    [ 5, 6, 6, 8, 9],
    [10,11,12,13,14],
    [15,16,17,18,19],
    [20,21,22,23,24]
]

rotate(matrix)

O código acima percorre as posições (linha e coluna) de todas as camadas que precisam ser rotacionadas.

Layer 0: first: 0, last: 4
Layer 1: first: 1, last: 3

Agora temos um loop fornecendo as posições das linhas e colunas de cada camada. As variáveis firste lastidentificam a posição do índice da primeira e da última linhas e colunas. Voltando às nossas tabelas de linhas e colunas:

+--------+-----------+
| Column | 0 1 2 3 4 |
+--------+-----------+
|        | . . . . . |
|        | . x x x . |
|        | . x O x . |
|        | . x x x . |
|        | . . . . . |
+--------+-----------+

+-----+-----------+
| Row |           |
+-----+-----------+
|   0 | . . . . . |
|   1 | . x x x . |
|   2 | . x O x . |
|   3 | . x x x . |
|   4 | . . . . . |
+-----+-----------+

Para que possamos navegar pelas camadas de uma matriz. Agora, precisamos de uma maneira de navegar dentro de uma camada para que possamos mover elementos ao redor dessa camada. Observe que os elementos nunca 'pulam' de uma camada para outra, mas se movem dentro de suas respectivas camadas.

Girar cada elemento em uma camada gira a camada inteira. A rotação de todas as camadas em uma matriz gira a matriz inteira. Esta frase é muito importante, então tente o seu melhor para entendê-la antes de prosseguir.

Agora, precisamos de uma maneira de realmente mover elementos, ou seja, girar cada elemento e, posteriormente, a camada e, finalmente, a matriz. Por simplicidade, reverteremos para uma matriz 3x3 - que possui uma camada rotativa.

0 1 2
3 4 5
6 7 8

Nosso loop de camada fornece os índices da primeira e da última coluna, bem como a primeira e a última linha:

+-----+-------+
| Col | 0 1 2 |
+-----+-------+
|     | 0 1 2 |
|     | 3 4 5 |
|     | 6 7 8 |
+-----+-------+

+-----+-------+
| Row |       |
+-----+-------+
|   0 | 0 1 2 |
|   1 | 3 4 5 |
|   2 | 6 7 8 |
+-----+-------+

Como nossas matrizes são sempre quadradas, precisamos de apenas duas variáveis firste last, como as posições do índice são as mesmas para linhas e colunas.

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2

    # Our layer loop i=0, i=1, i=2
    for layer in range(0, layer_count):

        first = layer
        last = size - first - 1

        # We want to move within a layer here.

As variáveis ​​first e last podem ser facilmente usadas para referenciar os quatro cantos de uma matriz. Isso ocorre porque os próprios cantos podem ser definidos usando várias permutações de firste last(sem subtração, adição ou deslocamento dessas variáveis):

+---------------+-------------------+-------------+
| Corner        | Position          | 3x3 Values  |
+---------------+-------------------+-------------+
| top left      | (first, first)    | (0,0)       |
| top right     | (first, last)     | (0,2)       |
| bottom right  | (last, last)      | (2,2)       |
| bottom left   | (last, first)     | (2,0)       |
+---------------+-------------------+-------------+

Por esse motivo, iniciamos nossa rotação nos quatro cantos externos - nós os rodaremos primeiro. Vamos destacá-los com *.

* 1 *
3 4 5
* 7 *

Queremos trocar cada *um *pela direita. Então, vamos em frente e imprima nossos cantos definidos usando apenas várias permutações de firste last:

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2
    for layer in range(0, layer_count):

        first = layer
        last = size - first - 1

        top_left = (first, first)
        top_right = (first, last)
        bottom_right = (last, last)
        bottom_left = (last, first)

        print 'top_left: %s' % (top_left)
        print 'top_right: %s' % (top_right)
        print 'bottom_right: %s' % (bottom_right)
        print 'bottom_left: %s' % (bottom_left)

matrix = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
]

rotate(matrix)

A saída deve ser:

top_left: (0, 0)
top_right: (0, 2)
bottom_right: (2, 2)
bottom_left: (2, 0)

Agora, podemos facilmente trocar cada um dos cantos de dentro do nosso loop de camada:

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2
    for layer in range(0, layer_count):

        first = layer
        last = size - first - 1

        top_left = matrix[first][first]
        top_right = matrix[first][last]
        bottom_right = matrix[last][last]
        bottom_left = matrix[last][first]

        # bottom_left -> top_left
        matrix[first][first] = bottom_left
        # top_left -> top_right
        matrix[first][last] = top_left
        # top_right -> bottom_right
        matrix[last][last] = top_right
        # bottom_right -> bottom_left
        matrix[last][first] = bottom_right


print_matrix(matrix)
print '---------'
rotate(matrix)
print_matrix(matrix)

Matriz antes de girar cantos:

[0, 1, 2]
[3, 4, 5]
[6, 7, 8]

Matriz depois de girar os cantos:

[6, 1, 0]
[3, 4, 5]
[8, 7, 2]

Ótimo! Giramos com sucesso cada canto da matriz. Mas não rotacionamos os elementos no meio de cada camada. Claramente, precisamos de uma maneira de iterar dentro de uma camada.

O problema é que o único loop em nossa função até agora (nosso loop de camada) passa para a próxima camada em cada iteração. Como nossa matriz possui apenas uma camada rotativa, o loop da camada sai após a rotação apenas dos cantos. Vejamos o que acontece com uma matriz 5 × 5 maior (onde duas camadas precisam ser rotacionadas). O código da função foi omitido, mas permanece o mesmo que acima:

matrix = [
[0, 1, 2, 3, 4],
[5, 6, 7, 8, 9],
[10, 11, 12, 13, 14],
[15, 16, 17, 18, 19],
[20, 21, 22, 23, 24]
]
print_matrix(matrix)
print '--------------------'
rotate(matrix)
print_matrix(matrix)

A saída é:

[20,  1,  2,  3,  0]
[ 5, 16,  7,  6,  9]
[10, 11, 12, 13, 14]
[15, 18, 17,  8, 19]
[24, 21, 22, 23,  4]

Não deve ser surpresa que os cantos da camada mais externa tenham sido girados, mas você também pode observar que os cantos da próxima camada (para dentro) também foram girados. Isso faz sentido. Escrevemos código para navegar pelas camadas e também para girar os cantos de cada camada. Parece um progresso, mas infelizmente devemos dar um passo atrás. Não adianta passar para a próxima camada até que a camada anterior (externa) tenha sido totalmente girada. Ou seja, até que cada elemento da camada seja girado. Girar apenas os cantos não serve!

Respire fundo. Precisamos de outro loop. Um loop aninhado não menos. O novo loop aninhado usará as variáveis firste last, além de um deslocamento para navegar dentro de uma camada. Vamos chamar esse novo loop de 'elemento loop'. O loop do elemento visitará cada elemento ao longo da linha superior, cada elemento no lado direito, cada elemento ao longo da linha inferior e cada elemento no lado esquerdo.

  • Para avançar na linha superior, é necessário aumentar o índice da coluna.
  • Mover para o lado direito requer que o índice da linha seja incrementado.
  • Mover para trás ao longo da parte inferior requer que o índice da coluna seja diminuído.
  • Mover para o lado esquerdo requer que o índice da linha seja diminuído.

Isso parece complexo, mas é fácil porque o número de vezes que aumentamos e diminuímos para alcançar o acima mencionado permanece o mesmo nos quatro lados da matriz. Por exemplo:

  • Mova 1 elemento pela linha superior.
  • Mova 1 elemento para o lado direito.
  • Mova 1 elemento para trás ao longo da linha inferior.
  • Mova 1 elemento para o lado esquerdo.

Isso significa que podemos usar uma única variável em combinação com as variáveis firste lastpara mover-se dentro de uma camada. Pode ser útil observar que a movimentação pela linha superior e pelo lado direito requer um incremento. Enquanto se move para trás ao longo da parte inferior e da esquerda, ambos exigem decréscimo.

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2

    # Move through layers (i.e. layer loop).
    for layer in range(0, layer_count):

            first = layer
            last = size - first - 1

            # Move within a single layer (i.e. element loop).
            for element in range(first, last):

                offset = element - first

                # 'element' increments column (across right)
                top_element = (first, element)
                # 'element' increments row (move down)
                right_side = (element, last)
                # 'last-offset' decrements column (across left)
                bottom = (last, last-offset)
                # 'last-offset' decrements row (move up)
                left_side = (last-offset, first)

                print 'top: %s' % (top)
                print 'right_side: %s' % (right_side)
                print 'bottom: %s' % (bottom)
                print 'left_side: %s' % (left_side)

Agora, basta atribuir o topo ao lado direito, o lado direito ao fundo, o fundo ao lado esquerdo e o lado esquerdo ao topo. Juntando tudo isso, obtemos:

def rotate(matrix):
    size = len(matrix)
    layer_count = size / 2

    for layer in range(0, layer_count):
        first = layer
        last = size - first - 1

        for element in range(first, last):
            offset = element - first

            top = matrix[first][element]
            right_side = matrix[element][last]
            bottom = matrix[last][last-offset]
            left_side = matrix[last-offset][first]

            matrix[first][element] = left_side
            matrix[element][last] = top
            matrix[last][last-offset] = right_side
            matrix[last-offset][first] = bottom

Dada a matriz:

0,  1,  2  
3,  4,  5  
6,  7,  8 

Nossa rotatefunção resulta em:

6,  3,  0  
7,  4,  1  
8,  5,  2  

Inicialmente, eu me senti como "uau, a melhor explicação de todos os tempos", mas depois de ler algumas vezes (para ter certeza de que não perdi nada importante no mar de palavras), minha opinião mudou para "cara, entendi, pode mantemos isso em movimento, por favor? " Ainda votado por tomar o que deve ter levado horas para compor uma resposta tão elaborada.
Abhijit Sarkar

1
@AbhijitSarkar - Obrigado pela votação antecipada e espero que pelo menos tenha ajudado de alguma maneira. Claro, você está certo, minha resposta é prolífica. No entanto, isso foi intencionalmente em contraste com a grande maioria das respostas. Como eu disse no começo da minha resposta: "Nesta resposta, conceitos-chave são repetidos, o ritmo é lento e intencionalmente repetitivo". Se você tem edições que mantêm a clareza e a repetitividade necessária, mas reduzem a contagem de palavras, estou muito aberto a sugestões. Ou simplesmente editar :)
Jack

@ Jack Realmente boa explicação. No entanto, eu não conseguia entender, como você criou offset = elemento - primeiro e último = tamanho - primeiro - 1? Tendo dificuldade em entender isso? Além disso, o último deslocamento é igual ao deslocamento?
Ashishjmeshram 28/05/19

1
TL; DR:list(zip(*reversed(your_list_of_lists)))
Boris

127

Pitão:

rotated = list(zip(*original[::-1]))

e anti-horário:

rotated_ccw = list(zip(*original))[::-1]

Como isso funciona:

zip(*original)trocará eixos de matrizes 2D, empilhando itens correspondentes das listas em novas listas. (O *operador diz à função para distribuir as listas contidas em argumentos)

>>> list(zip(*[[1,2,3],[4,5,6],[7,8,9]]))
[[1,4,7],[2,5,8],[3,6,9]]

A [::-1]instrução inverte os elementos da matriz (consulte Fatias estendidas ou esta pergunta ):

>>> [[1,2,3],[4,5,6],[7,8,9]][::-1]
[[7,8,9],[4,5,6],[1,2,3]]

Finalmente, a combinação dos dois resultará na transformação de rotação.

A mudança no posicionamento de [::-1]listas invertidas em diferentes níveis da matriz.


3
Eu acredito que este se origina de código de Peter Norvig: norvig.com/python-iaq.html
Josip

Você pode usar em zip(*reversed(original))vez de zip(*original[::-1])evitar criar uma cópia extra da lista original.
Boris

70

Aqui está um que faz a rotação no lugar em vez de usar uma matriz completamente nova para manter o resultado. Eu deixei de inicializar a matriz e imprimi-la. Isso funciona apenas para matrizes quadradas, mas elas podem ser de qualquer tamanho. A sobrecarga de memória é igual ao tamanho de um elemento da matriz, para que você possa fazer a rotação da matriz maior que desejar.

int a[4][4];
int n = 4;
int tmp;
for (int i = 0; i < n / 2; i++)
{
    for (int j = i; j < n - i - 1; j++)
    {
        tmp             = a[i][j];
        a[i][j]         = a[j][n-i-1];
        a[j][n-i-1]     = a[n-i-1][n-j-1];
        a[n-i-1][n-j-1] = a[n-j-1][i];
        a[n-j-1][i]     = tmp;
    }
}

Eu posso ver pelo menos um bug. Se você deseja publicar um código, teste-o ou, pelo menos, diga que não o fez.
Hugh Allen #

1
Onde? Apontar e eu vou consertar. Eu testei e funcionou bem em matrizes de tamanhos ímpares e pares.
Dagorym 04/10/08

2
é uma solução bonita. A mente pode realizar tais proezas se ajustada à finalidade. de O (n2) para O (1)
MoveFast

2
Não é O (1); ainda é O (n ^ 2)
duma

11
É O (n ^ 2) com memória O (1).
Neel

38

Existem muitos códigos bons aqui, mas eu só quero mostrar o que está acontecendo geometricamente, para que você possa entender um pouco melhor a lógica do código. Aqui está como eu abordaria isso.

Antes de tudo, não confunda isso com a transposição, que é muito fácil.

a idéia básica é tratá-lo como camadas e giramos uma camada por vez.

dizem que temos um 4x4

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

depois de girá-lo no sentido horário por 90, obtemos

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

então vamos decompor isso, primeiro giramos os 4 cantos essencialmente

1           4


13          16

então giramos o seguinte diamante, que é meio torto

    2
            8
9       
        15

e então o segundo diamante inclinado

        3
5           
            12
    14

para que cuide da borda externa, então essencialmente fazemos uma concha de cada vez até

finalmente o quadrado do meio (ou, se for estranho, apenas o elemento final que não se move)

6   7
10  11

então agora vamos descobrir os índices de cada camada, suponha que sempre trabalhemos com a camada mais externa, estamos fazendo

[0,0] -> [0,n-1], [0,n-1] -> [n-1,n-1], [n-1,n-1] -> [n-1,0], and [n-1,0] -> [0,0]
[0,1] -> [1,n-1], [1,n-2] -> [n-1,n-2], [n-1,n-2] -> [n-2,0], and [n-2,0] -> [0,1]
[0,2] -> [2,n-2], [2,n-2] -> [n-1,n-3], [n-1,n-3] -> [n-3,0], and [n-3,0] -> [0,2]

assim por diante até que estamos no meio da borda

então, em geral, o padrão é

[0,i] -> [i,n-i], [i,n-i] -> [n-1,n-(i+1)], [n-1,n-(i+1)] -> [n-(i+1),0], and [n-(i+1),0] to [0,i]

o que significa "na metade do caminho"? Eu vejo muitos algoritmos fazendo loop até N / 2 e outros fazendo loop até N, mas não consigo ver de onde vem o N / 2.
PDN

Eu acredito que é a mesma solução que foi dada em decifrar a entrevista de codificação. Mas eu gosto da explicação passo a passo. Muito agradável e completo.
Naphstor 8/11

@PDN Esta resposta explica em detalhes.
Mathias Bynens

35

Como eu disse no meu post anterior, aqui está um código em C # que implementa uma rotação da matriz O (1) para qualquer matriz de tamanho. Para concisão e legibilidade, não há verificação de erros ou verificação de alcance. O código:

static void Main (string [] args)
{
  int [,]
    //  create an arbitrary matrix
    m = {{0, 1}, {2, 3}, {4, 5}};

  Matrix
    //  create wrappers for the data
    m1 = new Matrix (m),
    m2 = new Matrix (m),
    m3 = new Matrix (m);

  //  rotate the matricies in various ways - all are O(1)
  m1.RotateClockwise90 ();
  m2.Rotate180 ();
  m3.RotateAnitclockwise90 ();

  //  output the result of transforms
  System.Diagnostics.Trace.WriteLine (m1.ToString ());
  System.Diagnostics.Trace.WriteLine (m2.ToString ());
  System.Diagnostics.Trace.WriteLine (m3.ToString ());
}

class Matrix
{
  enum Rotation
  {
    None,
    Clockwise90,
    Clockwise180,
    Clockwise270
  }

  public Matrix (int [,] matrix)
  {
    m_matrix = matrix;
    m_rotation = Rotation.None;
  }

  //  the transformation routines
  public void RotateClockwise90 ()
  {
    m_rotation = (Rotation) (((int) m_rotation + 1) & 3);
  }

  public void Rotate180 ()
  {
    m_rotation = (Rotation) (((int) m_rotation + 2) & 3);
  }

  public void RotateAnitclockwise90 ()
  {
    m_rotation = (Rotation) (((int) m_rotation + 3) & 3);
  }

  //  accessor property to make class look like a two dimensional array
  public int this [int row, int column]
  {
    get
    {
      int
        value = 0;

      switch (m_rotation)
      {
      case Rotation.None:
        value = m_matrix [row, column];
        break;

      case Rotation.Clockwise90:
        value = m_matrix [m_matrix.GetUpperBound (0) - column, row];
        break;

      case Rotation.Clockwise180:
        value = m_matrix [m_matrix.GetUpperBound (0) - row, m_matrix.GetUpperBound (1) - column];
        break;

      case Rotation.Clockwise270:
        value = m_matrix [column, m_matrix.GetUpperBound (1) - row];
        break;
      }

      return value;
    }

    set
    {
      switch (m_rotation)
      {
      case Rotation.None:
        m_matrix [row, column] = value;
        break;

      case Rotation.Clockwise90:
        m_matrix [m_matrix.GetUpperBound (0) - column, row] = value;
        break;

      case Rotation.Clockwise180:
        m_matrix [m_matrix.GetUpperBound (0) - row, m_matrix.GetUpperBound (1) - column] = value;
        break;

      case Rotation.Clockwise270:
        m_matrix [column, m_matrix.GetUpperBound (1) - row] = value;
        break;
      }
    }
  }

  //  creates a string with the matrix values
  public override string ToString ()
  {
    int
      num_rows = 0,
      num_columns = 0;

    switch (m_rotation)
    {
    case Rotation.None:
    case Rotation.Clockwise180:
      num_rows = m_matrix.GetUpperBound (0);
      num_columns = m_matrix.GetUpperBound (1);
      break;

    case Rotation.Clockwise90:
    case Rotation.Clockwise270:
      num_rows = m_matrix.GetUpperBound (1);
      num_columns = m_matrix.GetUpperBound (0);
      break;
    }

    StringBuilder
      output = new StringBuilder ();

    output.Append ("{");

    for (int row = 0 ; row <= num_rows ; ++row)
    {
      if (row != 0)
      {
        output.Append (", ");
      }

      output.Append ("{");

      for (int column = 0 ; column <= num_columns ; ++column)
      {
        if (column != 0)
        {
          output.Append (", ");
        }

        output.Append (this [row, column].ToString ());
      }

      output.Append ("}");
    }

    output.Append ("}");

    return output.ToString ();
  }

  int [,]
    //  the original matrix
    m_matrix;

  Rotation
    //  the current view of the matrix
    m_rotation;
}

OK, eu vou colocar minha mão, na verdade não faz nenhuma modificação na matriz original ao girar. Mas, em um sistema OO que não importa, desde que o objeto pareça ter sido rotacionado para os clientes da classe. No momento, a classe Matrix usa referências aos dados originais da matriz, portanto, alterar qualquer valor de m1 também mudará m2 e m3. Uma pequena alteração no construtor para criar uma nova matriz e copiar os valores para ela resolverá isso.


4
Bravo! Essa é uma solução muito boa e não sei por que não é a resposta aceita.
Martinatime 14/09/08

@martinatime: talvez porque seja 5 vezes maior
Toad

@Toad: Bem, escrever código é sempre uma troca entre requisitos concorrentes: velocidade, tamanho, custo etc.
Skizz

15
verdade ... outro problema é o fato de que a matriz não é de fato girada, mas é girada 'just in time'. O que é ótimo para acessar alguns elementos, mas seria horrível se essa matriz fosse usada em cálculos ou manipulações de imagens. Dizer O (1) não é realmente justo.
Toad

23

Embora a rotação dos dados no local possa ser necessária (talvez para atualizar a representação fisicamente armazenada), torna-se mais simples e possivelmente mais eficiente adicionar uma camada de indireção ao acesso ao array, talvez uma interface:

interface IReadableMatrix
{
    int GetValue(int x, int y);
}

Se você Matrixjá implementa essa interface, ela pode ser rotacionada por meio de uma classe decoradora como esta:

class RotatedMatrix : IReadableMatrix
{
    private readonly IReadableMatrix _baseMatrix;

    public RotatedMatrix(IReadableMatrix baseMatrix)
    {
        _baseMatrix = baseMatrix;
    }

    int GetValue(int x, int y)
    {
        // transpose x and y dimensions
        return _baseMatrix(y, x);
    }
}

Girar + 90 / -90 / 180 graus, inverter horizontalmente / verticalmente e dimensionar também podem ser alcançados dessa maneira.

O desempenho precisaria ser medido em seu cenário específico. No entanto, a operação O (n ^ 2) foi substituída por uma chamada O (1). É uma chamada de método virtual que é mais lenta que o acesso direto à matriz, portanto depende da frequência com que a matriz girada é usada após a rotação. Se for usado uma vez, então essa abordagem definitivamente venceria. Se for girado e usado em um sistema de longa execução por dias, a rotação no local poderá ter um desempenho melhor. Também depende se você pode aceitar o custo inicial.

Como em todos os problemas de desempenho, meça, meça, meça!


1
+1 ... E se a matriz é muito grande e você só acessar um elementos casal (uso esparso) é ainda mais eficaz
Lothar

16
Parece um pouco injusto chamar isso de solução de tempo O (1). Para resolver o problema proposto pelo OP, isso ainda levará tempo O (n ^ 2). Não apenas isso, ele não resolveria o problema porque retorna a transposição . O exemplo dado não tem a transposição como solução.
o perfil

5
Agora, se tudo o que você queria eram os 3 primeiros elementos da matriz, esta é uma solução ótima, mas o problema é recuperar uma matriz completamente transformada (isto é, supondo que você precise de todos os elementos da matriz). Chamar esse O (1) é o método Credit Default Swap de análise de algoritmos - você não resolveu o problema, você acabou empurrado para outra pessoa :)
Ana Betts

4
@ Paul Betts: Eu entendo o seu ponto de vista, mas como escrevi acima nos comentários, mesmo se você realmente tiver a matriz transposta, ainda precisará escrever o loop se quiser ler os valores. Portanto, a leitura de todos os valores de uma matriz é sempre O (N ^ 2), independentemente. A diferença aqui é que, se você transpõe, gira, escala, escala novamente, etc, você ainda recebe apenas o golpe O (N ^ 2) uma vez. Como eu disse, essa nem sempre é a melhor solução, mas em muitos casos é apropriada e vale a pena. O OP parecia estar procurando uma solução mágica, e isso é o mais próximo possível.
de Drew Noakes

9
Eu gosto desta resposta, mas quero apontar algo. Imprimir a matriz decorada (e fazer outras leituras seqüenciais em geral) pode ser muito mais lento do que fazer o mesmo com uma matriz que foi rotacionada na memória, e não é apenas por causa de chamadas de método virtual. Para uma grande matriz, você aumentará bastante o número de erros de cache que você lê lendo "inativo" em vez de "transversalmente".
Mike Daniels

18

Esta é uma versão melhor em Java: criei uma matriz com largura e altura diferentes

  • h é aqui a altura da matriz após a rotação
  • w é aqui a largura da matriz após a rotação

 

public int[][] rotateMatrixRight(int[][] matrix)
{
    /* W and H are already swapped */
    int w = matrix.length;
    int h = matrix[0].length;
    int[][] ret = new int[h][w];
    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            ret[i][j] = matrix[w - j - 1][i];
        }
    }
    return ret;
}


public int[][] rotateMatrixLeft(int[][] matrix)
{
    /* W and H are already swapped */
    int w = matrix.length;
    int h = matrix[0].length;   
    int[][] ret = new int[h][w];
    for (int i = 0; i < h; ++i) {
        for (int j = 0; j < w; ++j) {
            ret[i][j] = matrix[j][h - i - 1];
        }
    }
    return ret;
}

Este código é baseado na postagem de Nick Berardi.


Obrigado. Este foi o código Java mais claro aqui. Pergunta - Como você / Nick inventou a parte [w-j-1]? Olhando para a resposta @tweaking, posso ver como você pode derivar isso através de exemplos de indução / solução. Apenas me pergunto se foi assim que foi obtido ou se é baseado em algum princípio matemático relativo a Matrizes.
Quest Monger

17

Ruby-way: .transpose.map &:reverse


1
É ainda mais simples que isso: array.reverse.transposegira uma matriz no sentido horário, enquanto array.transpose.reversegira no sentido anti-horário. Não há necessidade map.
Giorgi Gzirishvili 11/07/19

13

Já existem muitas respostas e encontrei duas alegando complexidade de tempo O (1). O real algoritmo O (1) é deixar o armazenamento da matriz intocado e alterar a maneira como você indexa seus elementos. O objetivo aqui é que ele não consuma memória adicional, nem requer tempo adicional para iterar os dados.

Rotações de 90, -90 e 180 graus são transformações simples que podem ser executadas desde que você saiba quantas linhas e colunas existem em sua matriz 2D; Para girar qualquer vetor 90 graus, troque os eixos e negue o eixo Y. Para -90 graus, troque os eixos e negue o eixo X. Para 180 graus, negue os dois eixos sem trocar.

Outras transformações são possíveis, como espelhamento horizontal e / ou vertical, negando os eixos de forma independente.

Isso pode ser feito através, por exemplo, de um método acessador. Os exemplos abaixo são funções JavaScript, mas os conceitos se aplicam igualmente a todos os idiomas.

 // Get an array element in column/row order
 var getArray2d = function(a, x, y) {
   return a[y][x];
 };

 //demo
 var arr = [
   [5, 4, 6],
   [1, 7, 9],
   [-2, 11, 0],
   [8, 21, -3],
   [3, -1, 2]
 ];

 var newarr = [];
 arr[0].forEach(() => newarr.push(new Array(arr.length)));

 for (var i = 0; i < newarr.length; i++) {
   for (var j = 0; j < newarr[0].length; j++) {
     newarr[i][j] = getArray2d(arr, i, j);
   }
 }
 console.log(newarr);

// Get an array element rotated 90 degrees clockwise
function getArray2dCW(a, x, y) {
  var t = x;
  x = y;
  y = a.length - t - 1;
  return a[y][x];
}

//demo
var arr = [
  [5, 4, 6],
  [1, 7, 9],
  [-2, 11, 0],
  [8, 21, -3],
  [3, -1, 2]
];

var newarr = [];
arr[0].forEach(() => newarr.push(new Array(arr.length)));

for (var i = 0; i < newarr[0].length; i++) {
  for (var j = 0; j < newarr.length; j++) {
    newarr[j][i] = getArray2dCW(arr, i, j);
  }
}
console.log(newarr);

// Get an array element rotated 90 degrees counter-clockwise
function getArray2dCCW(a, x, y) {
  var t = x;
  x = a[0].length - y - 1;
  y = t;
  return a[y][x];
}

//demo
var arr = [
  [5, 4, 6],
  [1, 7, 9],
  [-2, 11, 0],
  [8, 21, -3],
  [3, -1, 2]
];

var newarr = [];
arr[0].forEach(() => newarr.push(new Array(arr.length)));

for (var i = 0; i < newarr[0].length; i++) {
  for (var j = 0; j < newarr.length; j++) {
    newarr[j][i] = getArray2dCCW(arr, i, j);
  }
}
console.log(newarr);

// Get an array element rotated 180 degrees
function getArray2d180(a, x, y) {
  x = a[0].length - x - 1;
  y = a.length - y - 1;
  return a[y][x];
}

//demo
var arr = [
  [5, 4, 6],
  [1, 7, 9],
  [-2, 11, 0],
  [8, 21, -3],
  [3, -1, 2]
];

var newarr = [];
arr.forEach(() => newarr.push(new Array(arr[0].length)));

for (var i = 0; i < newarr[0].length; i++) {
  for (var j = 0; j < newarr.length; j++) {
    newarr[j][i] = getArray2d180(arr, i, j);
  }
}
console.log(newarr);

Esse código assume uma matriz de matrizes aninhadas, onde cada matriz interna é uma linha.

O método permite que você leia (ou grave) elementos (mesmo em ordem aleatória) como se a matriz tivesse sido rotacionada ou transformada. Agora, basta escolher a função certa para ligar, provavelmente por referência, e pronto!

O conceito pode ser estendido para aplicar transformações de forma aditiva (e não destrutiva) através dos métodos de acessador. Incluindo rotações arbitrárias de ângulo e escala.


No entanto, nenhum deles girou da matriz original. O primeiro, o resultado final é simplesmente transposto. O segundo, você parece ter apenas embaralhado as linhas ou espelhado no centro horizontal. O terceiro, você apenas inverteu as linhas e o quarto também é transposto. Nenhum dos quais foi realmente "rotacionado".
SM177Y

Existem alguns erros nos dois últimos exemplos. Trivial para corrigir. Eu indiquei explicitamente que esta solução não é uma rotação no local. É uma função de transformação, o que o torna adequado para iteração lenta.
Jason Oster

Exceto que não há rotação, então você realmente não respondeu ao que o OP pediu.
SM177Y

@ SM177Y Outro editor adicionou um código de exemplo que não funciona à minha resposta. Eu posso ver como você estava confuso com isso. Corrigi os erros nos loops de iteração. As funções fornecidas de fato "rotacionam" os dados nas matrizes.
Jason Oster

Outro detalhe importante é que o código de exemplo realmente explica a resposta original que eu forneci, que estava tentando ilustrar o poder das transformações funcionais sobre as soluções lineares de complexidade espaço-tempo. Com uma transformação funcional, você está iterando ou acessando os elementos da matriz , de modo que a transformação é considerada "livre" no sentido de complexidade constante de espaço e tempo.
Jason Oster

10

Algumas pessoas já colocaram exemplos que envolvem a criação de uma nova matriz.

Algumas outras coisas a considerar:

(a) Em vez de realmente mover os dados, basta percorrer a matriz "rotacionada" de maneira diferente.

(b) Fazer a rotação no local pode ser um pouco mais complicado. Você precisará de um pouco de espaço inicial (provavelmente igual a uma linha ou coluna). Há um artigo antigo da ACM sobre a realização de transposições no local ( http://doi.acm.org/10.1145/355719.355729 ), mas o código de exemplo deles é o FORTRAN desagradável e carregado de goto.

Termo aditivo:

http://doi.acm.org/10.1145/355611.355612 é outro algoritmo de transposição local supostamente superior.


Eu concordo com isto. Tenha um método que determine a conversão entre os dados de origem e os dados "rotacionados".
Martinatime 14/09/08

8

A resposta de Nick também funcionaria para uma matriz NxM com apenas uma pequena modificação (em oposição a uma NxN).

string[,] orig = new string[n, m];
string[,] rot = new string[m, n];

...

for ( int i=0; i < n; i++ )
  for ( int j=0; j < m; j++ )
    rot[j, n - i - 1] = orig[i, j];

Uma maneira de pensar sobre isso é que você moveu o centro do eixo (0,0) do canto superior esquerdo para o canto superior direito. Você está simplesmente transpondo de um para o outro.


6

Tempo - O (N), Espaço - O (1)

public void rotate(int[][] matrix) {
    int n = matrix.length;
    for (int i = 0; i < n / 2; i++) {
        int last = n - 1 - i;
        for (int j = i; j < last; j++) {
            int top = matrix[i][j];
            matrix[i][j] = matrix[last - j][i];
            matrix[last - j][i] = matrix[last][last - j];
            matrix[last][last - j] = matrix[j][last];
            matrix[j][last] = top;
        }
    }
}

Este não é O (1). Este é O (n).
Jason Oster

@JasonOster Acredito que este seja o espaço O (1), pois não consome espaço adicional.
Ffledgling 27/10/2014

@ffledgling Meu erro. O (1) complexidade do espaço, sim. O (n) complexidade do tempo.
Jason Oster

A complexidade do espaço também é O (n). A complexidade do espaço deve incluir o espaço do tamanho da variável de entrada. careercup.com/question?id=14952322
Jason Heo

Como eu poderia modificar isso para funcionar em uma rotação no sentido anti-horário?
MD XF

5

Aqui está minha versão do Ruby (observe que os valores não são exibidos da mesma forma, mas ainda assim gira como descrito).

def rotate(matrix)
  result = []
  4.times { |x|
    result[x] = []
    4.times { |y|
      result[x][y] = matrix[y][3 - x]
    }
  }

  result
end

matrix = []
matrix[0] = [1,2,3,4]
matrix[1] = [5,6,7,8]
matrix[2] = [9,0,1,2]
matrix[3] = [3,4,5,6]

def print_matrix(matrix)
  4.times { |y|
    4.times { |x|
      print "#{matrix[x][y]} "
    }
    puts ""
  }
end

print_matrix(matrix)
puts ""
print_matrix(rotate(matrix))

A saída:

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

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

4

aqui está um método de rotação no espaço, por java, apenas para quadrado. para uma matriz 2D não quadrada, você precisará criar uma nova matriz de qualquer maneira.

private void rotateInSpace(int[][] arr) {
    int z = arr.length;
    for (int i = 0; i < z / 2; i++) {
        for (int j = 0; j < (z / 2 + z % 2); j++) {
            int x = i, y = j;
            int temp = arr[x][y];
            for (int k = 0; k < 4; k++) {
                int temptemp = arr[y][z - x - 1];
                arr[y][z - x - 1] = temp;
                temp = temptemp;

                int tempX = y;
                y = z - x - 1;
                x = tempX;
            }
        }
    }
}

código para girar qualquer matriz 2D de tamanho criando uma nova matriz:

private int[][] rotate(int[][] arr) {
    int width = arr[0].length;
    int depth = arr.length;
    int[][] re = new int[width][depth];
    for (int i = 0; i < depth; i++) {
        for (int j = 0; j < width; j++) {
            re[j][depth - i - 1] = arr[i][j];
        }
    }
    return re;
}

3

Implementação do pseudocódigo +90 da covinha (por exemplo, transpor e reverter cada linha) em JavaScript:

function rotate90(a){
  // transpose from http://www.codesuck.com/2012/02/transpose-javascript-array-in-one-line.html
  a = Object.keys(a[0]).map(function (c) { return a.map(function (r) { return r[c]; }); });
  // row reverse
  for (i in a){
    a[i] = a[i].reverse();
  }
  return a;
}

3

Você pode fazer isso em 3 etapas fáceis :

1 ) Suponha que tenhamos uma matriz

   1 2 3
   4 5 6
   7 8 9

2 ) Faça a transposição da matriz

   1 4 7
   2 5 8
   3 6 9

3 ) Troque linhas para obter a matriz rotacionada

   3 6 9
   2 5 8
   1 4 7

Código-fonte Java para isso:

public class MyClass {

    public static void main(String args[]) {
        Demo obj = new Demo();
        /*initial matrix to rotate*/
        int[][] matrix = { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 } };
        int[][] transpose = new int[3][3]; // matrix to store transpose

        obj.display(matrix);              // initial matrix

        obj.rotate(matrix, transpose);    // call rotate method
        System.out.println();
        obj.display(transpose);           // display the rotated matix
    }
}

class Demo {   
    public void rotate(int[][] mat, int[][] tran) {

        /* First take the transpose of the matrix */
        for (int i = 0; i < mat.length; i++) {
            for (int j = 0; j < mat.length; j++) {
                tran[i][j] = mat[j][i]; 
            }
        }

        /*
         * Interchange the rows of the transpose matrix to get rotated
         * matrix
         */
        for (int i = 0, j = tran.length - 1; i != j; i++, j--) {
            for (int k = 0; k < tran.length; k++) {
                swap(i, k, j, k, tran);
            }
        }
    }

    public void swap(int a, int b, int c, int d, int[][] arr) {
        int temp = arr[a][b];
        arr[a][b] = arr[c][d];
        arr[c][d] = temp;    
    }

    /* Method to display the matrix */
    public void display(int[][] arr) {
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr.length; j++) {
                System.out.print(arr[i][j] + " ");
            }
            System.out.println();
        }
    }
}

Resultado:

1 2 3 
4 5 6 
7 8 9 

3 6 9 
2 5 8 
1 4 7 

2

Esta é minha implementação, na complexidade da memória C, O (1), rotação no local, 90 graus no sentido horário:

#include <stdio.h>

#define M_SIZE 5

static void initMatrix();
static void printMatrix();
static void rotateMatrix();

static int m[M_SIZE][M_SIZE];

int main(void){
    initMatrix();
    printMatrix();
    rotateMatrix();
    printMatrix();

    return 0;
}

static void initMatrix(){
    int i, j;

    for(i = 0; i < M_SIZE; i++){
        for(j = 0; j < M_SIZE; j++){
            m[i][j] = M_SIZE*i + j + 1;
        }
    }
}

static void printMatrix(){
    int i, j;

    printf("Matrix\n");
    for(i = 0; i < M_SIZE; i++){
        for(j = 0; j < M_SIZE; j++){
            printf("%02d ", m[i][j]);
        }
        printf("\n");
    }
    printf("\n");
}

static void rotateMatrix(){
    int r, c;

    for(r = 0; r < M_SIZE/2; r++){
        for(c = r; c < M_SIZE - r - 1; c++){
            int tmp = m[r][c];

            m[r][c] = m[M_SIZE - c - 1][r];
            m[M_SIZE - c - 1][r] = m[M_SIZE - r - 1][M_SIZE - c - 1];
            m[M_SIZE - r - 1][M_SIZE - c - 1] = m[c][M_SIZE - r - 1];
            m[c][M_SIZE - r - 1] = tmp;
        }
    }
}

2

Aqui está a versão do Java:

public static void rightRotate(int[][] matrix, int n) {
    for (int layer = 0; layer < n / 2; layer++) {
        int first = layer;
        int last = n - 1 - first;
        for (int i = first; i < last; i++) {
           int offset = i - first;
           int temp = matrix[first][i];
           matrix[first][i] = matrix[last-offset][first];
           matrix[last-offset][first] = matrix[last][last-offset];
           matrix[last][last-offset] = matrix[i][last];
           matrix[i][last] = temp;
        }
    }
}

o método primeiro rotaciona a camada maisouter e depois move para a camada interna de maneira esquemática.


2

De um ponto de vista linear, considere as matrizes:

    1 2 3        0 0 1
A = 4 5 6    B = 0 1 0
    7 8 9        1 0 0

Agora faça uma transposição

     1 4 7
A' = 2 5 8
     3 6 9

E considere a ação de A 'em B ou B em A'.
Respectivamente:

      7 4 1          3 6 9
A'B = 8 5 2    BA' = 2 5 8
      9 6 3          1 4 7

Isso é expansível para qualquer matriz nxn. E aplicando esse conceito rapidamente no código:

void swapInSpace(int** mat, int r1, int c1, int r2, int c2)
{
    mat[r1][c1] ^= mat[r2][c2];
    mat[r2][c2] ^= mat[r1][c1];
    mat[r1][c1] ^= mat[r2][c2];
}

void transpose(int** mat, int size)
{
    for (int i = 0; i < size; i++)
    {
        for (int j = (i + 1); j < size; j++)
        {
            swapInSpace(mat, i, j, j, i);
        }
    }
}

void rotate(int** mat, int size)
{
    //Get transpose
    transpose(mat, size);

    //Swap columns
    for (int i = 0; i < size / 2; i++)
    {
        for (int j = 0; j < size; j++)
        {
            swapInSpace(mat, i, j, size - (i + 1), j);
        }
    }
}

2

Código C # para girar [n, m] matrizes 2D 90 graus à direita

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace MatrixProject
{
    // mattrix class

    class Matrix{
        private int rows;
        private int cols;
        private int[,] matrix;

        public Matrix(int n){
            this.rows = n;
            this.cols = n;
            this.matrix = new int[this.rows,this.cols];

        }

        public Matrix(int n,int m){
            this.rows = n;
            this.cols = m;

            this.matrix = new int[this.rows,this.cols];
        }

        public void Show()
        {
            for (var i = 0; i < this.rows; i++)
            {
                for (var j = 0; j < this.cols; j++) {
                    Console.Write("{0,3}", this.matrix[i, j]);
                }
                Console.WriteLine();
            }                
        }

        public void ReadElements()
        {
           for (var i = 0; i < this.rows; i++)
                for (var j = 0; j < this.cols; j++)
                {
                    Console.Write("element[{0},{1}]=",i,j);
                    this.matrix[i, j] = Convert.ToInt32(Console.ReadLine());
                }            
        }


        // rotate [n,m] 2D array by 90 deg right
        public void Rotate90DegRight()
        {

            // create a mirror of current matrix
            int[,] mirror = this.matrix;

            // create a new matrix
            this.matrix = new int[this.cols, this.rows];

            for (int i = 0; i < this.rows; i++)
            {
                for (int j = 0; j < this.cols; j++)
                {
                    this.matrix[j, this.rows - i - 1] = mirror[i, j];
                }
            }

            // replace cols count with rows count
            int tmp = this.rows;
            this.rows = this.cols;
            this.cols = tmp;           
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            Matrix myMatrix = new Matrix(3,4);
            Console.WriteLine("Enter matrix elements:");
            myMatrix.ReadElements();
            Console.WriteLine("Matrix elements are:");
            myMatrix.Show();
            myMatrix.Rotate90DegRight();
            Console.WriteLine("Matrix rotated at 90 deg are:");
            myMatrix.Show();
            Console.ReadLine();
        }
    }
}

Resultado:

    Enter matrix elements:
    element[0,0]=1
    element[0,1]=2
    element[0,2]=3
    element[0,3]=4
    element[1,0]=5
    element[1,1]=6
    element[1,2]=7
    element[1,3]=8
    element[2,0]=9
    element[2,1]=10
    element[2,2]=11
    element[2,3]=12
    Matrix elements are:
      1  2  3  4
      5  6  7  8
      9 10 11 12
    Matrix rotated at 90 deg are:
      9  5  1
     10  6  2
     11  7  3
     12  8  4

2

PHP:

<?php    
$a = array(array(1,2,3,4),array(5,6,7,8),array(9,0,1,2),array(3,4,5,6));
$b = array(); //result

while(count($a)>0)
{
    $b[count($a[0])-1][] = array_shift($a[0]);
    if (count($a[0])==0)
    {
         array_shift($a);
    }
}

No PHP5.6, a transposição da matriz pode ser realizada com uma array_map()chamada lenta . Em outras palavras, as colunas são convertidas em linhas.

Código: ( Demo )

$array = [
    [1, 2, 3, 4],
    [5, 6, 7, 8],
    [9, 0, 1, 2],
    [3, 4, 5, 6]
];
$transposed = array_map(null, ...$array);

$ transposto:

[
    [1, 5, 9, 3],
    [2, 6, 0, 4],
    [3, 7, 1, 5],
    [4, 8, 2, 6]
]

1

For i:= 0 to X do For j := 0 to X do graphic[j][i] := graphic2[X-i][j]

X é o tamanho da matriz em que o gráfico se encontra.


1

#transpose é um método padrão da classe Ruby Array, portanto:

% irb
irb(main):001:0> m = [[1, 2, 3, 4], [5, 6, 7, 8], [9, 0, 1, 2], [3, 4, 5, 6]]
=> [[1, 2, 3, 4], [5, 6, 7, 8], [9, 0, 1, 2], [3, 4, 5, 6]] 
irb(main):002:0> m.reverse.transpose
=> [[3, 9, 5, 1], [4, 0, 6, 2], [5, 1, 7, 3], [6, 2, 8, 4]]

A implementação é uma função de transposição n ^ 2 escrita em C. Você pode vê-la aqui: http://www.ruby-doc.org/core-1.9.3/Array.html#method-i-transpose escolhendo "clique em" para alternar a fonte "ao lado de" transpor ".

Lembro-me melhor que as soluções O (n ^ 2), mas apenas para matrizes especialmente construídas (como matrizes esparsas)


1

Código C para rotação da matriz 90 graus no sentido horário NO LOCAL para qualquer matriz M * N

void rotateInPlace(int * arr[size][size], int row, int column){
    int i, j;
    int temp = row>column?row:column;
    int flipTill = row < column ? row : column;
    for(i=0;i<flipTill;i++){
        for(j=0;j<i;j++){
            swapArrayElements(arr, i, j);
        }
    }

    temp = j+1;

    for(i = row>column?i:0; i<row; i++){
            for(j=row<column?temp:0; j<column; j++){
                swapArrayElements(arr, i, j);
            }
    }

    for(i=0;i<column;i++){
        for(j=0;j<row/2;j++){
            temp = arr[i][j];
            arr[i][j] = arr[i][row-j-1];
            arr[i][row-j-1] = temp;
        }
    }
}

1

aqui está minha implementação no local em C

void rotateRight(int matrix[][SIZE], int length) {

    int layer = 0;

    for (int layer = 0; layer < length / 2; ++layer) {

        int first = layer;
        int last = length - 1 - layer;

        for (int i = first; i < last; ++i) {

            int topline = matrix[first][i];
            int rightcol = matrix[i][last];
            int bottomline = matrix[last][length - layer - 1 - i];
            int leftcol = matrix[length - layer - 1 - i][first];

            matrix[first][i] = leftcol;
            matrix[i][last] = topline;
            matrix[last][length - layer - 1 - i] = rightcol;
            matrix[length - layer - 1 - i][first] = bottomline;
        }
    }
}

1

Aqui está minha tentativa de rotação de 90 graus da matriz, que é uma solução em duas etapas em C. Primeiro transponha a matriz no lugar e depois troque as colunas.

#define ROWS        5
#define COLS        5

void print_matrix_b(int B[][COLS], int rows, int cols) 
{
    for (int i = 0; i <= rows; i++) {
        for (int j = 0; j <=cols; j++) {
            printf("%d ", B[i][j]);
        }
        printf("\n");
    }
}

void swap_columns(int B[][COLS], int l, int r, int rows)
{
    int tmp;
    for (int i = 0; i <= rows; i++) {
        tmp = B[i][l];
        B[i][l] = B[i][r];
        B[i][r] = tmp;
    }
}


void matrix_2d_rotation(int B[][COLS], int rows, int cols)
{
    int tmp;
    // Transpose the matrix first
    for (int i = 0; i <= rows; i++) {
        for (int j = i; j <=cols; j++) {
            tmp = B[i][j];
            B[i][j] = B[j][i];
            B[j][i] = tmp;
        }
    }
    // Swap the first and last col and continue until
    // the middle.
    for (int i = 0; i < (cols / 2); i++)
        swap_columns(B, i, cols - i, rows);
}



int _tmain(int argc, _TCHAR* argv[])
{
    int B[ROWS][COLS] = { 
                  {1, 2, 3, 4, 5}, 
                      {6, 7, 8, 9, 10},
                          {11, 12, 13, 14, 15},
                          {16, 17, 18, 19, 20},
                          {21, 22, 23, 24, 25}
                        };

    matrix_2d_rotation(B, ROWS - 1, COLS - 1);

    print_matrix_b(B, ROWS - 1, COLS -1);
    return 0;
}

1

@dagorym: Ah, cara. Eu tinha me apegado a isso como um bom quebra-cabeça "Estou entediado, o que posso ponderar". Eu vim com meu código de transposição no local, mas cheguei aqui para encontrar o seu praticamente idêntico ao meu ... ah, bem. Aqui está em Ruby.

require 'pp'
n = 10
a = []
n.times { a << (1..n).to_a }

pp a

0.upto(n/2-1) do |i|
  i.upto(n-i-2) do |j|
    tmp             = a[i][j]
    a[i][j]         = a[n-j-1][i]
    a[n-j-1][i]     = a[n-i-1][n-j-1]
    a[n-i-1][n-j-1] = a[j][n-i-1]
    a[j][n-i-1]     = tmp
  end
end

pp a

1
short normal[4][4] = {{8,4,7,5},{3,4,5,7},{9,5,5,6},{3,3,3,3}};

short rotated[4][4];

for (int r = 0; r < 4; ++r)
{
  for (int c = 0; c < 4; ++c)
  {
    rotated[r][c] = normal[c][3-r];
  }
}

Método C ++ simples, embora houvesse uma grande sobrecarga de memória em uma grande matriz.


Entre todas estas respostas que eu encontrei e testou este que é compacto e suficiente para rodar
dlewin
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.