Un ami avait besoin d'un algorithme qui lui permettrait de parcourir les éléments d'une matrice NxM (N et M sont impairs). J'ai trouvé une solution, mais je voulais voir si mes collègues SO'ers pouvaient trouver une meilleure solution.
Je poste ma solution en réponse à cette question.
Exemple de sortie:
Pour une matrice 3x3, la sortie doit être:
(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1 )
De plus, l'algorithme doit prendre en charge les matrices non carrées, donc par exemple pour une matrice 5x3, la sortie doit être:
(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)
Réponses:
Voici ma solution (en Python):
la source
C ++ quelqu'un? Traduction rapide de python, publiée par souci d'exhaustivité
la source
Il y a eu de nombreuses solutions proposées pour ce problème écrites dans divers langages de programmation, mais elles semblent toutes provenir de la même approche alambiquée. Je vais considérer le problème plus général du calcul d'une spirale qui peut être exprimée de manière concise en utilisant l'induction.
Cas de base: Commencez à (0, 0), avancez d'1 case, tournez à gauche, avancez d'1 case, tournez à gauche. Pas inductif: Avancez de n + 1 carrés, tournez à gauche, avancez de n + 1 carrés, tournez à gauche.
L'élégance mathématique de l'expression de ce problème suggère fortement qu'il devrait y avoir un algorithme simple pour calculer la solution. En gardant à l'esprit l'abstraction, j'ai choisi de ne pas implémenter l'algorithme dans un langage de programmation spécifique mais plutôt sous forme de pseudo-code.
Je vais d'abord considérer un algorithme pour calculer seulement 2 itérations de la spirale en utilisant 4 paires de boucles while. La structure de chaque paire est similaire, mais distincte en soi. Cela peut sembler fou au début (certaines boucles ne sont exécutées qu'une seule fois) mais pas à pas, je vais faire des transformations jusqu'à ce que nous arrivions à 4 paires de boucles identiques et pouvant donc être remplacées par une seule paire placée à l'intérieur d'une autre boucle. Cela nous fournira une solution générale de calcul de n itérations sans utiliser de conditionnelles.
La première transformation que nous allons faire est l'introduction d'une nouvelle variable d, pour la direction, qui contient la valeur +1 ou -1. La direction change après chaque paire de boucles. Puisque nous connaissons la valeur de d en tous points, nous pouvons multiplier chaque côté de chaque inégalité par elle, ajuster la direction de l'inégalité en conséquence et simplifier toute multiplication de d par une constante à une autre constante. Cela nous laisse avec ce qui suit.
Maintenant, nous notons que x * d et le RHS sont des entiers, nous pouvons donc soustraire toute valeur réelle entre 0 et 1 du RHS sans affecter le résultat de l'inégalité. Nous choisissons de soustraire 0,5 des inégalités de chaque autre paire de boucles while afin d'établir davantage un modèle.
Nous pouvons maintenant introduire une autre variable m pour le nombre de pas que nous faisons à chaque paire de boucles while.
Enfin, on voit que la structure de chaque paire de boucles while est identique et peut se réduire à une seule boucle placée à l'intérieur d'une autre boucle. Aussi, pour éviter d'utiliser des nombres réels, j'ai multiplié la valeur initiale de m; la valeur m est incrémentée de; et les deux côtés de chaque inégalité par 2.
Cela conduit à la solution indiquée au début de cette réponse.
la source
Voici une solution O (1) pour trouver la position dans une spirale carrée: Fiddle
la source
if (n === 0) return [0, 0, r]; --n;
Voir Fiddle: jsfiddle.net/Wishmesh/nwd9gt1s/2J'adore les générateurs de python.
Tester avec:
Vous obtenez:
la source
Tentative de "Code golf" en spirale Java, basée sur la variante C ++.
la source
Voici une solution C ++ qui montre que vous pouvez calculer les coordonnées suivantes (x, y) directement et facilement à partir des précédentes - pas besoin de suivre la direction, le rayon ou autre chose:
Si tout ce que vous essayez de faire est de générer les N premiers points de la spirale (sans la contrainte du problème d'origine de masquer une région N x M), le code devient très simple:
L'astuce est que vous pouvez comparer x et y pour déterminer de quel côté du carré vous vous trouvez, et cela vous indique dans quelle direction aller.
la source
TDD, en Java.
SpiralTest.java:
Spiral.java:
la source
Voici ma solution (en rubis)
la source
Haskell, faites votre choix:
la source
C'est en C.
J'ai choisi de mauvais noms de variables. Dans les noms T == haut, L == gauche, B == bas, R == droite. Donc, tli est en haut à gauche i et brj en bas à droite j.
la source
J'ai une bibliothèque open source, pixelscan , qui est une bibliothèque python qui fournit des fonctions pour numériser des pixels sur une grille dans une variété de modèles spatiaux. Les motifs spatiaux inclus sont les circulaires, les anneaux, les grilles, les serpents et les marches aléatoires. Il existe également diverses transformations (par exemple, couper, permuter, faire pivoter, traduire). Le problème OP d'origine peut être résolu comme suit
qui rapporte les points
Les générateurs de bibliothèques et les transformations peuvent être enchaînés pour changer les points dans une grande variété d'ordres et de modèles spatiaux.
la source
Voici une solution en Python 3 pour imprimer des entiers consécutifs dans une spirale dans le sens horaire et antihoraire.
Explication
Une spirale est composée de carrés concentriques, par exemple un carré de 5x5 avec une rotation dans le sens des aiguilles d'une montre ressemble à ceci:
(
>>>>>
signifie "aller 5 fois à droite" ou augmenter l'index de colonne 5 fois,v
signifie diminuer ou augmenter l'index de ligne, etc.)Tous les carrés sont identiques jusqu'à leur taille, j'ai bouclé sur les carrés concentriques.
Pour chaque carré, le code a quatre boucles (une pour chaque côté), dans chaque boucle nous augmentons ou diminuons les colonnes ou l'index de ligne. Si
i
est l'index de ligne etj
l'index de colonne, alors un carré de 5x5 peut être construit en: - incrémentantj
de 0 à 4 (5 fois) - incrémentanti
de 1 à 4 (4 fois) - décrémentantj
de 3 à 0 (4 fois) - décrémentanti
de 3 à 1 (3 fois)Pour les carrés suivants (3x3 et 1x1), nous faisons de même mais décalons les indices initial et final de manière appropriée. J'ai utilisé un index
k
pour chaque carré concentrique, il y a n // 2 + 1 carrés concentriques.Enfin, quelques maths pour une jolie impression.
Pour imprimer les index:
la source
Voici c #, linq'ish.
Le premier exemple de la question (3x3) serait:
Le deuxième exemple de la question (5x3) serait:
la source
Ceci est une version légèrement différente - essayant d'utiliser
recursion
etiterators
dans LUA. A chaque étape, le programme descend plus loin à l'intérieur de la matrice et boucle. J'ai également ajouté un drapeau supplémentaire à spiralclockwise
ouanticlockwise
. La sortie commence à partir des coins inférieurs droit et effectue une boucle récursive vers le centre.la source
// Implémentation PHP
la source
Voici une solution itérative JavaScript (ES6) à ce problème:
Voici comment l'utiliser:
spiralMatrix(0, 0, 1, 100);
Cela créera une spirale vers l'extérieur, commençant aux coordonnées (x = 0, y = 0) avec un pas de 1 et un nombre total d'éléments égal à 100. La mise en œuvre démarre toujours le mouvement dans l'ordre suivant - haut, droite, bas, la gauche.
Veuillez noter que cette implémentation crée des matrices carrées.
la source
Voici une réponse dans Julia: mon approche consiste à attribuer les points en carrés concentriques (`` spirales '') autour de l'origine
(0,0)
, où chaque carré a une longueur de côtém = 2n + 1
, pour produire un dictionnaire ordonné avec des numéros d'emplacement (à partir de 1 pour l'origine) comme clés et la coordonnée correspondante comme valeur.Puisque l'emplacement maximum par spirale est à
(n,-n)
, le reste des points peut être trouvé en travaillant simplement en arrière à partir de ce point, c'est-à-dire à partir du coin inférieur droit parm-1
unités, puis en répétant pour les 3 segments perpendiculaires dem-1
unités .Ce processus est écrit dans l'ordre inverse ci-dessous, correspondant à la façon dont la spirale se déroule plutôt qu'à ce processus de comptage inversé, c'est-à-dire que le
ra
segment [ascendant à droite] est décrémenté de3(m+1)
, puisla
[ascendant à gauche] de2(m+1)
, et ainsi de suite - j'espère que cela s'explique par lui-même .Donc, pour votre premier exemple, vous connecter
m = 3
à l'équation pour trouver n donnen = (5-1)/2 = 2
, etwalk(2)
donne un dictionnaire ordonné d'emplacements en coordonnées, que vous pouvez transformer en un simple tableau de coordonnées en accédant auvals
champ du dictionnaire :Notez que pour certaines fonctions [par exemple
norm
], il peut être préférable de laisser les coordonnées dans des tableaux plutôt queTuple{Int,Int}
, mais ici je les change en tuples—(x,y)
- comme demandé, en utilisant la compréhension de liste.Le contexte de "prise en charge" d'une matrice non carrée n'est pas spécifié (notez que cette solution calcule toujours les valeurs hors grille), mais si vous souhaitez filtrer uniquement la plage
x
pary
(ici pourx=5
,y=3
) après avoir calculé la spirale complète puisintersect
cette matrice contre les valeurs dewalk
.la source
Votre question ressemble à une question appelée mémoire en spirale. Dans ce problème, chaque carré de la grille est alloué selon un motif en spirale à partir du numéro 1 qui se situe à l'origine. Et puis compter en montant en spirale vers l'extérieur. Par exemple:
Ma solution pour calculer les coordonnées de chaque nombre suivant ce modèle en spirale est postée ci-dessous:
la source
Ceci est basé sur votre propre solution, mais nous pouvons être plus intelligents pour trouver les coins. Cela permet de voir plus facilement comment vous pourriez sauter les zones à l'extérieur si M et N sont très différents.
et une solution basée sur un générateur qui est meilleure que O (max (n, m) ^ 2), C'est O (nm + abs (nm) ^ 2) car elle saute des bandes entières si elles ne font pas partie de la solution.
la source
la source
C'est ma très très mauvaise solution, faite à partir d'une connaissance minimale de Java. Ici, je dois placer des unités sur un champ en spirale. Les unités ne peuvent pas être placées au-dessus d'autres unités ou sur des montagnes ou dans l'océan.
Pour être clair. Ce n'est pas une bonne solution. C'est une très mauvaise solution ajoutée pour le plaisir des autres à rire de la façon dont cela peut être mal fait
Cudos à tous ceux qui peuvent réellement lire ceci
Question bonus: Quelle est la durée de fonctionnement de cet "algorithme"? : P
la source
Solution pour AutoIt
la source
J'ai récemment eu un défi similaire où j'ai dû créer un tableau 2D et utiliser un algorithme de matrice en spirale pour trier et imprimer les résultats. Ce code C # fonctionnera avec un tableau N, N 2D. Il est détaillé pour plus de clarté et peut probablement être retravaillé pour répondre à vos besoins.
la source
J'ai fait celui-ci avec un ami qui ajuste la spirale au rapport hauteur / largeur de la toile sur Javascript. La meilleure solution que j'ai eue pour une évolution d'image pixel par pixel, remplissant l'image entière.
J'espère que cela aide quelqu'un.
Vous pouvez le voir fonctionner sur http://jsfiddle.net/hitbyatruck/c4Kd6/ . Assurez-vous simplement de changer la largeur et la hauteur du canevas sur les vars javascript et sur les attributs sur le HTML.
la source
Juste pour s'amuser en Javascript:
la source
Version C #, gère également les tailles non carrées.
la source
Je partage ce code que j'ai conçu dans un but différent; il s'agit de trouver le numéro de colonne "X" et le numéro de ligne "Y" de l'élément de tableau @ spiral index "index". Cette fonction prend la largeur "w" et la hauteur "h" de la matrice, ainsi que l '"index" requis. Bien entendu, cette fonction peut être utilisée pour produire la même sortie requise. Je pense que c'est la méthode la plus rapide possible (car elle saute par-dessus les cellules au lieu de les scanner).
la source
Python bouclant le code en spirale dans le sens des aiguilles d'une montre en utilisant la réponse Can Berk Güder .
la source
L'excellente solution de Davidont dans VB.Net
la source