Znajomy potrzebował algorytmu, który pozwoliłby mu przeglądać elementy macierzy NxM (N i M są nieparzyste). Wymyśliłem rozwiązanie, ale chciałem sprawdzić, czy moi koledzy z SO mogą znaleźć lepsze rozwiązanie.
W odpowiedzi na to pytanie zamieszczam moje rozwiązanie.
Przykładowe dane wyjściowe:
W przypadku macierzy 3x3 wynik powinien wyglądać następująco:
(0, 0) (1, 0) (1, 1) (0, 1) (-1, 1) (-1, 0) (-1, -1) (0, -1) (1, -1 )
Ponadto algorytm powinien obsługiwać macierze niekwadratowe, więc na przykład dla macierzy 5x3 wynik powinien wyglądać następująco:
(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)
Odpowiedzi:
Oto moje rozwiązanie (w Pythonie):
źródło
C ++ ktoś? Szybkie tłumaczenie z Pythona, opublikowane dla kompletności
źródło
Było wiele propozycji rozwiązań tego problemu napisanych w różnych językach programowania, jednak wszystkie wydają się wynikać z tego samego zawiłego podejścia. Rozważę bardziej ogólny problem obliczania spirali, którą można zwięźle wyrazić za pomocą indukcji.
Podstawowy przypadek: zacznij od (0, 0), przejdź do przodu o 1 pole, skręć w lewo, przejdź do przodu o 1 pole, skręć w lewo. Krok indukcyjny: przesuń się do przodu o n + 1 pól, skręć w lewo, przejdź do przodu o n + 1 kwadratów, skręć w lewo.
Matematyczna elegancja wyrażenia tego problemu silnie sugeruje, że powinien istnieć prosty algorytm obliczania rozwiązania. Pamiętając o abstrakcji, zdecydowałem się nie implementować algorytmu w konkretnym języku programowania, ale raczej jako pseudokod.
Najpierw rozważę algorytm obliczający tylko 2 iteracje spirali przy użyciu 4 par pętli while. Struktura każdej pary jest podobna, ale odrębna na swój sposób. Na początku może się to wydawać szalone (niektóre pętle są wykonywane tylko raz), ale krok po kroku będę dokonywać transformacji, aż dojdziemy do 4 identycznych par pętli, które można zastąpić pojedynczą parą umieszczoną w innej pętli. To zapewni nam ogólne rozwiązanie obliczania n iteracji bez używania jakichkolwiek warunków.
Pierwszą transformacją, której dokonamy, będzie wprowadzenie nowej zmiennej d dla kierunku, która ma wartość +1 lub -1. Kierunek zmienia się po każdej parze pętli. Ponieważ znamy wartość d we wszystkich punktach, możemy pomnożyć przez nią każdą stronę każdej nierówności, odpowiednio dostosować kierunek nierówności i uprościć wszelkie mnożenia d przez stałą do innej stałej. Pozostaje nam to, co następuje.
Teraz zauważamy, że zarówno x * d, jak i RHS są liczbami całkowitymi, więc możemy odjąć dowolną wartość rzeczywistą z zakresu od 0 do 1 od RHS bez wpływu na wynik nierówności. Decydujemy się odjąć 0,5 od nierówności każdej innej pary pętli while, aby uzyskać więcej wzoru.
Możemy teraz wprowadzić inną zmienną m dla liczby kroków, które wykonujemy w każdej parze pętli while.
Wreszcie widzimy, że struktura każdej pary pętli while jest identyczna i można ją zredukować do pojedynczej pętli umieszczonej wewnątrz innej pętli. Ponadto, aby uniknąć używania liczb o wartościach rzeczywistych, pomnożyłem początkową wartość m; wartość m jest zwiększana o; i obie strony każdej nierówności o 2.
Prowadzi to do rozwiązania przedstawionego na początku tej odpowiedzi.
źródło
Oto rozwiązanie O (1) pozwalające znaleźć pozycję w kwadratowej spirali: Skrzypce
źródło
if (n === 0) return [0, 0, r]; --n;
Zobacz Fiddle: jsfiddle.net/Wishmesh/nwd9gt1s/2Uwielbiam generatory Pythona.
Testowanie z:
Dostajesz:
źródło
Próba spirali Java „Code golf”, oparta na wariancie C ++.
źródło
Oto rozwiązanie w C ++, które pokazuje, że możesz obliczyć następne współrzędne (x, y) bezpośrednio i łatwo na podstawie poprzednich - nie ma potrzeby śledzenia bieżącego kierunku, promienia lub czegokolwiek innego:
Jeśli wszystko, co próbujesz zrobić, to wygenerować pierwsze N punktów spirali (bez ograniczenia pierwotnego problemu do maskowania do regionu N x M), kod staje się bardzo prosty:
Sztuczka polega na tym, że możesz porównać x i y, aby określić, po której stronie kwadratu się znajdujesz, a to mówi ci, w jakim kierunku się poruszać.
źródło
TDD w Javie.
SpiralTest.java:
Spiral.java:
źródło
Oto moje rozwiązanie (w języku Ruby)
źródło
Haskell, wybierz:
źródło
To jest w C.
Zdarzyło mi się wybrać złe nazwy zmiennych. W nazwach T == góra, L == lewa, B == dół, R == prawa. Zatem tli jest lewym górnym i, a brj jest prawym dolnym j.
źródło
Mam bibliotekę open source, pixelscan , która jest biblioteką Pythona, która zapewnia funkcje do skanowania pikseli na siatce w różnych wzorach przestrzennych. Uwzględnione wzory przestrzenne to okrągłe, pierścienie, siatki, węże i przypadkowe spacery. Istnieją również różne transformacje (np. Przycinanie, zamiana, obracanie, tłumaczenie). Pierwotny problem z OP można rozwiązać w następujący sposób
co daje punkty
Biblioteki generatorów i transformacji można łączyć w łańcuchy, aby zmieniać punkty w wielu różnych porządkach i wzorach przestrzennych.
źródło
Oto rozwiązanie w Pythonie 3 do drukowania kolejnych liczb całkowitych po spirali zgodnie z ruchem wskazówek zegara i przeciwnie do ruchu wskazówek zegara.
Wyjaśnienie
Spirala składa się z koncentrycznych kwadratów, na przykład kwadrat 5x5 obracający się w prawo wygląda następująco:
(
>>>>>
oznacza „idź 5 razy w prawo” lub zwiększ indeks kolumny 5 razy,v
oznacza zmniejsz lub zwiększ indeks wierszy itp.)Wszystkie kwadraty są takie same, jeśli chodzi o ich rozmiar. Przejechałem pętlą po koncentrycznych kwadratach.
Dla każdego kwadratu kod ma cztery pętle (po jednej na każdą stronę), w każdej pętli zwiększamy lub zmniejszamy indeks kolumn lub wierszy. Jeśli
i
jest indeksem wiersza i indeksemj
kolumny, to kwadrat 5x5 można skonstruować przez: - zwiększaniej
od 0 do 4 (5 razy) - zwiększaniei
od 1 do 4 (4 razy) - zmniejszaniej
od 3 do 0 (4 razy) - zmniejszaniei
od 3 do 1 (3 razy)Dla następnych kwadratów (3x3 i 1x1) robimy to samo, ale odpowiednio przesuwamy indeksy początkowy i końcowy. Użyłem indeksu
k
dla każdego koncentrycznego kwadratu, jest n // 2 + 1 koncentrycznych kwadratów.Na koniec trochę matematyki do ładnego drukowania.
Aby wydrukować indeksy:
źródło
Oto c #, linq'ish.
Pierwszy przykład pytania (3x3) brzmiałby:
Drugi przykład pytania (5x3) wyglądałby tak:
źródło
To jest nieco inna wersja - próbuję używać
recursion
iwiterators
LUA. Na każdym kroku program schodzi dalej w matrycę i pętle. Dodałem również dodatkową flagę do spiraliclockwise
lubanticlockwise
. Dane wyjściowe zaczynają się od dolnych prawych rogów i zapętlają się rekurencyjnie w kierunku środka.źródło
// Implementacja PHP
źródło
Oto iteracyjne rozwiązanie tego problemu w JavaScript (ES6):
Oto jak go używać:
spiralMatrix(0, 0, 1, 100);
Stworzy to zewnętrzną spiralę, zaczynającą się od współrzędnych (x = 0, y = 0) z krokiem 1 i całkowitą liczbą elementów równą 100. Realizacja zawsze rozpoczyna ruch w następującej kolejności - w górę, w prawo, w dół, lewo.
Proszę zauważyć, że ta implementacja tworzy macierze kwadratowe.
źródło
Oto odpowiedź w Julii: moje podejście polega na przypisaniu punktów w koncentrycznych kwadratach (`` spiralach '') wokół początku
(0,0)
, gdzie każdy kwadrat ma długość bokum = 2n + 1
, w celu utworzenia uporządkowanego słownika z numerami lokalizacji (zaczynając od 1 dla początku) jako kluczy i odpowiednia współrzędna jako wartość.Ponieważ maksymalne położenie na spiralę znajduje się w
(n,-n)
, pozostałe punkty można znaleźć, po prostu wykonując od tego punktu wstecz, tj. Od prawego dolnego rogu, om-1
jednostki, a następnie powtarzając dla prostopadłych 3 segmentówm-1
jednostek.Ten proces jest zapisany poniżej w odwrotnej kolejności, odpowiadającej temu, jak przebiega spirala, a nie odwrotnemu procesowi liczenia, tj.
ra
Segment [rosnący w prawo] jest zmniejszany o3(m+1)
, a następniela
[rosnący w lewo] o2(m+1)
itd. - Mam nadzieję, że jest to oczywiste .Tak więc w pierwszym przykładzie podłączenie
m = 3
się do równania w celu znalezienia n dajen = (5-1)/2 = 2
iwalk(2)
daje uporządkowany słownik lokalizacji współrzędnych, który można przekształcić w tablicę współrzędnych, uzyskując dostęp dovals
pola słownika :Zauważ, że w przypadku niektórych funkcji [np.
norm
] Może być lepiej pozostawienie współrzędnych w tablicach niżTuple{Int,Int}
, ale tutaj zamieniam je na krotki(x,y)
- - zgodnie z życzeniem, używając funkcji list złożonych .Kontekst dla „wspieranie” non-kwadrat matryca nie jest określona (uwaga, że to rozwiązanie wciąż oblicza wartości off-grid), ale jeśli chcesz, aby filtrować tylko zakresie
x
przezy
(tutajx=5
,y=3
) po obliczeniu pełną spiralę następnieintersect
ta macierz w stosunku do wartości zwalk
.źródło
Twoje pytanie wygląda jak pytanie zwane pamięcią spiralną. W tym zadaniu każdy kwadrat na siatce jest przydzielony spiralnie, zaczynając od cyfry 1, która znajduje się u początku. A potem zliczanie podczas spirali na zewnątrz. Na przykład:
Moje rozwiązanie do obliczania współrzędnych każdej liczby według tego wzoru spiralnego znajduje się poniżej:
źródło
Jest to oparte na Twoim własnym rozwiązaniu, ale możemy być mądrzejsi w znajdowaniu narożników. Ułatwia to zorientowanie się, w jaki sposób można pominąć obszary na zewnątrz, jeśli M i N są bardzo różne.
i rozwiązanie oparte na generatorze, które jest lepsze niż O (max (n, m) ^ 2), to jest O (nm + abs (nm) ^ 2), ponieważ pomija całe paski, jeśli nie są częścią roztworu.
źródło
źródło
To jest moje bardzo złe rozwiązanie, oparte na minimalnej znajomości języka Java. Tutaj muszę umieścić jednostki na polu w spiralę. Jednostki nie mogą być umieszczane na innych jednostkach ani na górach ani w oceanie.
Żeby było jasne. To nie jest dobre rozwiązanie. To bardzo złe rozwiązanie dodane dla zabawy innych ludzi, aby śmiać się z tego, jak źle można to zrobić
Cudos dla każdego, kto może to przeczytać
Pytanie dodatkowe: Jaki jest czas działania tego „algorytmu”? : P
źródło
Rozwiązanie dla AutoIt
źródło
Niedawno miałem podobne wyzwanie, w którym musiałem utworzyć tablicę 2D i użyć algorytmu matrycy spiralnej do sortowania i drukowania wyników. Ten kod C # będzie działał z tablicą 2D N, N. Dla jasności jest on rozwlekły i prawdopodobnie może zostać zmieniony w celu dostosowania do Twoich potrzeb.
źródło
Zrobiłem to z przyjacielem, który dostosowuje spiralę do proporcji płótna w JavaScript. Najlepsze rozwiązanie jakie otrzymałem dla ewolucji obrazu piksel po pikselu, wypełniając cały obraz.
Mam nadzieję, że to komuś pomoże.
Możesz zobaczyć, jak działa na http://jsfiddle.net/hitbyatruck/c4Kd6/ . Po prostu pamiętaj, aby zmienić szerokość i wysokość płótna w zmiennych javascript i atrybutach w HTML.
źródło
Dla zabawy w Javascript:
źródło
Wersja C # obsługuje również rozmiary inne niż kwadratowe.
źródło
Dzielę się tym kodem, który zaprojektowałem w innym celu; chodzi o znalezienie numeru kolumny „X” i numeru wiersza „Y” elementu tablicy @ indeks spirali „indeks”. Ta funkcja pobiera szerokość „w” i wysokość „h” macierzy oraz wymagany „indeks”. Oczywiście ta funkcja może być użyta do uzyskania takiego samego wymaganego wyniku. Myślę, że jest to najszybsza możliwa metoda (przeskakuje komórki zamiast je skanować).
źródło
Python zapętla spiralny kod zgodnie z ruchem wskazówek zegara, używając odpowiedzi Can Berk Güder .
źródło
Doskonałe rozwiązanie firmy Davidont w VB.Net
źródło