Um amigo precisava de um algoritmo que o deixasse percorrer os elementos de uma matriz NxM (N e M são ímpares). Eu vim com uma solução, mas queria ver se meus colegas SO'ers poderiam encontrar uma solução melhor.
Estou postando minha solução como resposta a esta pergunta.
Saída de exemplo:
Para uma matriz 3x3, a saída deve ser:
(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1 )
Além disso, o algoritmo deve suportar matrizes não quadradas, portanto, por exemplo, para uma matriz 5x3, a saída deve ser:
(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1 ) (2, -1) (2, 0) (2, 1) (-2, 1) (-2, 0) (-2, -1)
Respostas:
Aqui está a minha solução (em Python):
fonte
C ++ alguém? Tradução rápida de python, postada para completar
fonte
Existem muitas soluções propostas para esse problema escritas em várias linguagens de programação, no entanto, todas elas parecem resultar da mesma abordagem complicada. Vou considerar o problema mais geral de calcular uma espiral que pode ser expressa de forma concisa usando indução.
Caso base: comece em (0, 0), avance 1 quadrado, vire à esquerda, avance 1 quadrado, vire à esquerda. Passo indutivo: avançar n + 1 quadrados, virar à esquerda, avançar n + 1 quadrados, virar à esquerda.
A elegância matemática de expressar esse problema sugere fortemente que deve haver um algoritmo simples para calcular a solução. Mantendo a abstração em mente, decidi não implementar o algoritmo em uma linguagem de programação específica, mas como pseudo-código.
Primeiro, considerarei um algoritmo para calcular apenas 2 iterações da espiral usando 4 pares de loops while. A estrutura de cada par é semelhante, mas distinta por si só. Isso pode parecer louco no começo (alguns loops são executados apenas uma vez), mas passo a passo farei transformações até chegarmos a 4 pares de loops que são idênticos e, portanto, podem ser substituídos por um único par colocado dentro de outro loop. Isso nos fornecerá uma solução geral de iterações de computação sem o uso de condicionais.
A primeira transformação que faremos é a introdução de uma nova variável d, para direção, que contém o valor +1 ou -1. A direção muda após cada par de loops. Como conhecemos o valor de d em todos os pontos, podemos multiplicar cada lado de cada desigualdade por ele, ajustar a direção da desigualdade de acordo e simplificar qualquer multiplicação de d por uma constante para outra constante. Isso nos deixa com o seguinte.
Agora observamos que x * d e o RHS são números inteiros, portanto podemos subtrair qualquer valor real entre 0 e 1 do RHS sem afetar o resultado da desigualdade. Optamos por subtrair 0,5 das desigualdades de todos os outros pares de loops while, a fim de estabelecer mais um padrão.
Agora podemos introduzir outra variável m para o número de etapas que seguimos em cada par de loops while.
Finalmente, vemos que a estrutura de cada par de loops while é idêntica e pode ser reduzida a um único loop colocado dentro de outro loop. Além disso, para evitar o uso de números reais, multipliquei o valor inicial de m; o valor m é incrementado por; e ambos os lados de cada desigualdade por 2.
Isso leva à solução mostrada no início desta resposta.
fonte
Aqui está uma solução O (1) para encontrar a posição em uma espiral quadrada: Fiddle
fonte
if (n === 0) return [0, 0, r]; --n;
Veja Fiddle: jsfiddle.net/Wishmesh/nwd9gt1s/2Eu amo os geradores de python.
Testando com:
Você obtém:
fonte
Tentativa de "código golf" em espiral de Java, com base na variante C ++.
fonte
Aqui está uma solução C ++ que mostra que você pode calcular as próximas coordenadas (x, y) direta e facilmente das anteriores - não há necessidade de rastrear a direção atual, raio ou qualquer outra coisa:
Se tudo o que você está tentando fazer é gerar os primeiros N pontos na espiral (sem a restrição do problema original de mascarar em uma região N x M), o código se torna muito simples:
O truque é que você pode comparar x e y para determinar em que lado do quadrado você está, e isso indica em que direção você deve se mover.
fonte
TDD, em Java.
SpiralTest.java:
Spiral.java:
fonte
Aqui está a minha solução (em Ruby)
fonte
Haskell, faça a sua escolha:
fonte
Isso está em C.
Por acaso escolhi nomes de variáveis ruins. Nos nomes T == superior, L == esquerda, B == inferior, R == direita. Então, tli é superior esquerdo ie brj é inferior direito j.
fonte
Eu tenho uma biblioteca de código aberto, pixelscan , que é uma biblioteca python que fornece funções para digitalizar pixels em uma grade em uma variedade de padrões espaciais. Os padrões espaciais incluídos são circulares, anéis, grades, cobras e passeios aleatórios. Existem também várias transformações (por exemplo, recortar, trocar, girar, traduzir). O problema do OP original pode ser resolvido da seguinte maneira
que produz os pontos
Os geradores e transformações das bibliotecas podem ser encadeados para alterar os pontos em uma ampla variedade de ordens e padrões espaciais.
fonte
Aqui está uma solução no Python 3 para imprimir números inteiros consecutivos em espiral no sentido horário e anti-horário.
Explicação
Uma espiral é feita de quadrados concêntricos, por exemplo, um quadrado de 5x5 com rotação no sentido horário é assim:
(
>>>>>
significa "avançar 5 vezes à direita" ou aumentar o índice da coluna 5 vezes,v
diminuir ou aumentar o índice da linha etc.)Todos os quadrados são iguais até o tamanho, passei pelos quadrados concêntricos.
Para cada quadrado, o código possui quatro loops (um para cada lado), em cada loop aumentamos ou diminuímos o índice de colunas ou linhas. Se
i
é o índice da linha ej
o índice da coluna, um quadrado de 5x5 pode ser construído por: - incrementandoj
de 0 a 4 (5 vezes) - incrementandoi
de 1 a 4 (4 vezes) - decrescendoj
de 3 a 0 (4 vezes) - diminuindoi
de 3 a 1 (3 vezes)Para os próximos quadrados (3x3 e 1x1), fazemos o mesmo, mas alteramos os índices inicial e final adequadamente. Eu usei um índice
k
para cada quadrado concêntrico, existem n // 2 + 1 quadrados concêntricos.Finalmente, um pouco de matemática para impressão bonita.
Para imprimir os índices:
fonte
Aqui está c #, linq'ish.
O primeiro exemplo da pergunta (3x3) seria:
O segundo exemplo da pergunta (5x3) seria:
fonte
Esta é uma versão ligeiramente diferente - tentando usar
recursion
eiterators
no LUA. A cada passo, o programa desce mais para dentro da matriz e faz loops. Também adicionei uma bandeira extra em espiralclockwise
ouanticlockwise
. A saída começa nos cantos inferiores direito e volta repetidamente em direção ao centro.fonte
// implementação do PHP
fonte
Aqui está uma solução iterativa JavaScript (ES6) para esse problema:
Veja como usá-lo:
spiralMatrix(0, 0, 1, 100);
Isso criará uma espiral externa, iniciando nas coordenadas (x = 0, y = 0) com a etapa 1 e um número total de itens igual a 100. A implementação sempre inicia o movimento na seguinte ordem - para cima, direita, baixo, esquerda.
Por favor, observe que esta implementação cria matrizes quadradas.
fonte
Aqui está uma resposta em Julia: minha abordagem é atribuir os pontos em quadrados concêntricos ('espirais') ao redor da origem
(0,0)
, onde cada quadrado tem comprimento lateralm = 2n + 1
, para produzir um dicionário ordenado com números de localização (a partir de 1 para a origem) como chaves e a coordenada correspondente como valor.Como a localização máxima por espiral está em
(n,-n)
, o restante dos pontos pode ser encontrado simplesmente trabalhando para trás a partir deste ponto, ou seja, no canto inferior direito porm-1
unidades, repetindo para os 3 segmentos dem-1
unidades perpendiculares .Esse processo é escrito na ordem inversa abaixo, correspondendo à maneira como a espiral prossegue, e não ao processo de contagem inversa, ou seja, o
ra
segmento [ascendente reto] é decrementado por3(m+1)
, depoisla
[ascendente esquerdo] por2(m+1)
e assim por diante - espero que seja autoexplicativo .Portanto, para o seu primeiro exemplo, conectar
m = 3
-se à equação para encontrar n fornecen = (5-1)/2 = 2
ewalk(2)
fornece um dicionário ordenado de locais para coordenadas, que você pode transformar em apenas uma matriz de coordenadas acessando ovals
campo do dicionário :Observe que, para algumas funções [por exemplo
norm
], pode ser preferível deixar as coordenadas em matrizes, em vez deTuple{Int,Int}
, mas aqui eu as altero para tuplas(x,y)
- conforme solicitado, usando a compreensão da lista.O contexto para "apoiar" uma matriz não-quadrado não é especificado (note que esta solução ainda calcula os valores fora da rede), mas se você quiser filtro para apenas o intervalo
x
dey
(aqui parax=5
,y=3
) depois de calcular a espiral completa entãointersect
esta matriz contra os valores dewalk
.fonte
Sua pergunta parece uma pergunta chamada memória espiral. Nesse problema, cada quadrado na grade é alocado em um padrão em espiral a partir do número 1 que se localiza na origem. E então contando enquanto espiralando para fora. Por exemplo:
Minha solução para calcular as coordenadas de cada número seguindo este padrão em espiral é publicada abaixo:
fonte
Isso se baseia em sua própria solução, mas podemos ser mais inteligentes em encontrar os cantos. Isso facilita a visualização de como você pode pular as áreas externas se M e N forem muito diferentes.
e uma solução baseada em gerador que é melhor que O (max (n, m) ^ 2), é O (nm + abs (nm) ^ 2) porque pula tiras inteiras se elas não fazem parte da solução.
fonte
fonte
Esta é a minha solução muito ruim, feita a partir do conhecimento mínimo de Java. Aqui eu tenho que colocar unidades em um campo em espiral. As unidades não podem ser colocadas em cima de outras unidades ou nas montanhas ou no oceano.
Para ser claro. Esta não é uma boa solução. Esta é uma solução muito ruim adicionada para a diversão de outras pessoas rirem do quão ruim isso pode ser feito
Cudos para quem pode realmente ler isso
Pergunta bônus: Qual é o tempo de execução desse "algoritmo"? : P
fonte
Solução para AutoIt
fonte
Recentemente, tive um desafio semelhante em que tive que criar uma matriz 2D e usar um algoritmo de matriz espiral para classificar e imprimir os resultados. Esse código C # funcionará com uma matriz N, N 2D. É detalhado para maior clareza e provavelmente pode ser re-fatorado para atender às suas necessidades.
fonte
Fiz este com um amigo que ajusta a espiral à proporção da tela em Javascript. Melhor solução que obtive para uma evolução da imagem pixel por pixel, preenchendo a imagem inteira.
Espero que ajude alguém.
Você pode vê-lo trabalhando em http://jsfiddle.net/hitbyatruck/c4Kd6/ . Apenas certifique-se de alterar a largura e a altura da tela nos vars javascript e nos atributos no HTML.
fonte
Apenas por diversão em Javascript:
fonte
Versão C #, também manipula tamanhos não quadrados.
fonte
Estou compartilhando esse código que criei para uma finalidade diferente; trata-se de encontrar o número da coluna "X" e o número da linha "Y" do elemento da matriz @ índice espiral "índice". Esta função usa a largura "w" e a altura "h" da matriz e o "índice" necessário. Obviamente, essa função pode ser usada para produzir a mesma saída necessária. Eu acho que é o método mais rápido possível (como ele pula as células em vez de examiná-las).
fonte
Python loopando código espiral no sentido horário usando a resposta de Can Berk Güder .
fonte
Excelente solução de Davidont em VB.Net
fonte