Zadanie
- Otrzymujesz zmienny ciąg pasujący
[a-z]+( [a-z]+)*
. - Musisz zmutować go do ciągu zawierającego te same słowa, ale w odwrotnej kolejności, aby „cześć wszyscy” zamieniło się w „wszyscy tam cześć”.
- Nie wolno używać więcej niż stałej ilości dodatkowej pamięci (więc nie kopiuj całego łańcucha lub jakiegokolwiek słowa do właśnie przydzielonego bufora).
- Nie ma ograniczeń czasowych. Bycie beznadziejnie nieefektywnym nie zaszkodzi twojemu wynikowi.
- Jeśli wybrany język nie pozwala na mutację łańcuchów, tablice znaków są akceptowalnym zamiennikiem.
Twój wynik
- Twój wynik jest liczony wyłącznie na podstawie liczby przypisań do elementów ciągów (najlepsze są małe wyniki). Jeśli użyjesz funkcji biblioteki, która zapisuje ciąg, jego zapisy również się liczą.
- Załóżmy, że liczba przypisań potrzebnych do wprowadzenia s wynosi n (s) . Zatem twój wynik jest maksymalny (pedantycznie, supremum) na wszystkich wejściach s (pasujących do wyrażenia regularnego określonego powyżej) n (s) / długości (s) . Jeśli nie możesz tego dokładnie obliczyć, możesz użyć najniższej górnej granicy, którą możesz udowodnić.
- Możesz zerwać remis, jeśli możesz udowodnić, że twój algorytm używa asymptotycznie mniej przydziałów (może się to zdarzyć, nawet jeśli masz ten sam wynik, patrz poniżej). Jeśli nie możesz tego zrobić, możesz zerwać remis, pokazując, że zużywasz mniej dodatkowej pamięci. Jednak pierwszy warunek rozstrzygnięcia zawsze ma pierwszeństwo.
- W przypadku niektórych danych wejściowych każda postać musi się zmienić, więc nie można zdobyć mniej niż 1.
- Mogę wymyślić prosty algorytm z wynikiem 2 (ale go nie wprowadzam).
Uwagi na temat supremy i więzi
- Supremum zbioru liczb jest najmniejszą liczbą, która nie jest mniejsza od żadnej z nich. Jest to bardzo podobne do maksimum zestawu, z tym wyjątkiem, że niektóre zestawy nieskończone, takie jak {2/3, 3/4, 4/5, 5/6, ...}, nie mają pojedynczego maksymalnego elementu, ale nadal będą miały supremum, w tym przypadku 1.
- Jeśli uda ci się „zapisać” tylko stałą liczbę zadań w moim algorytmie wyniku 2 (powiedzmy), twój wynik będzie nadal wynosił 2, ponieważ dowolnie zbliżysz się do 2, tym większy będzie twój wkład. Jeśli jednak do tego dojdzie, wygrywasz w dogrywce.
code-challenge
Ben Millwood
źródło
źródło
little-omega(1)
przestrzeń, umieszczając ją na stosie.O(1)
dodatkową przestrzenią. PotrzebujeszO(log n)
miejsca do przechowywania pozycji indeksu, ponieważ k-bitowa liczba całkowita może przechowywać w nich tylko łańcuchy o długości do2^k
. Ograniczenie długości ciągów sprawia, że wyzwanie jest raczej bezcelowe, ponieważ każdy algorytm wymagałby wO(1)
ten sposób miejsca.Odpowiedzi:
Python, wynik:
21,51,25Jest to bezpośrednia kombinacja między odpowiedzią primo a moją odpowiedzią. Podziękowania dla niego także!
Dowód jest wciąż w toku, ale oto kod do zabawy! Jeśli możesz znaleźć przeciwny przykład wyniku większego niż 1,25 (lub jeśli występuje błąd), daj mi znać!
Obecnie najgorszym przypadkiem jest:
gdzie jest dokładnie n każdej z liter „a”, „b”, „c” i „” (spacja) oraz dokładnie dwa „d”. Długość ciągu wynosi 4n + 2, a liczba zadań wynosi 5n + 2 , co daje wynik 5/4 = 1,25 .
Algorytm działa w dwóch krokach:
k
takie, żestring[k]
istring[n-1-k]
są granice słowostring[:k]+string[n-1-k:]
(tj. Łączenie pierwszegok
i ostatniegok
znaku) z niewielką modyfikacją.gdzie
n
jest długość łańcucha.Ulepszenie, jakie daje ten algorytm, pochodzi z „małej modyfikacji” w kroku 2. Zasadniczo wiedza polega na tym, że w połączonym łańcuchu znaki w pozycji
k
ik+1
granice słów (co oznacza, że są spacjami lub pierwszym / ostatnim znakiem w słowie), dzięki czemu możemy bezpośrednio zastąpić znaki na miejscuk
ik+1
odpowiednim znakiem w ostatnim ciągu, zapisując kilka przypisań. To usuwa najgorszy przypadek z algorytmu odwracania słów hostaSą przypadki, w których tak naprawdę nie możemy ich znaleźć
k
, w takim przypadku po prostu uruchamiamy „algorytm odwracania dowolnego słowa” na całym ciągu.Kod długo obsługuje te cztery przypadki po uruchomieniu algorytmu odwracania słów w łańcuchu „konkatenowanym”:
k
nie znaleziono (f_long = -2
)string[k] != ' ' and string[n-1-k] != ' '
(f_long = 0
)string[k] != ' ' and string[n-1-k] == ' '
(f_long = 1
)string[k] == ' ' and string[n-1-k] != ' '
(f_long = -1
)Jestem pewien, że kod można skrócić. Obecnie jest długi, ponieważ na początku nie miałem wyraźnego obrazu całego algorytmu. Jestem pewien, że można zaprojektować go tak, aby był reprezentowany przez krótszy kod =)
Przykładowy przebieg (pierwszy to mój, drugi to primo):
Widać, że wynik jest prawie taki sam, z wyjątkiem najgorszego przypadku algorytmu odwracania słów hosta w trzecim przykładzie, dla którego moje podejście daje wynik mniejszy niż 1,25
Python, wynik: 1,5
Dokładną liczbę zadań można oszacować według wzoru:
w najgorszym przypadku:
z 55 przypisaniami na sznurku o długości 37.
Pomysł jest podobny do mojego poprzedniego, po prostu w tej wersji próbowałem znaleźć prefiks i sufiks na granicach słów z różnicą długości co najwyżej 1. Następnie uruchamiam mój poprzedni algorytm na tym prefiksie i sufiksie (wyobraź sobie, że są one połączone) . Następnie przejdź do części nieprzetworzonej.
Na przykład w poprzednim najgorszym przypadku:
najpierw dokonamy zamiany słów na „ab” i „c” (4 przypisania), aby:
Wiemy, że na granicy była kiedyś spacja (istnieje wiele przypadków do załatwienia, ale można to zrobić), więc nie musimy kodować spacji na granicy, jest to główna poprawa w stosunku do poprzedniego algorytmu .
Następnie biegniemy na środkowych czterech postaciach, aby uzyskać:
w sumie 8 zadań, co jest optymalne w tym przypadku, ponieważ wszystkie 8 znaków uległo zmianie.
Eliminuje to najgorszy przypadek w poprzednim algorytmie, ponieważ najgorszy przypadek w poprzednim algorytmie został wyeliminowany.
Zobacz przykładowy przebieg (i porównanie z odpowiedzią @ primo - jego to druga linia):
Odpowiedź primo jest na ogół lepsza, chociaż w niektórych przypadkach mogę mieć 1 punkt przewagi =)
Również jego kod jest znacznie krótszy niż mój, haha.
Python, wynik: asymptotycznie 2, w normalnym przypadku znacznie mniej
stary kod został usunięty z powodu ograniczenia miejsca
Chodzi o iterację po każdym indeksie, a dla każdego indeksu
i
bierzemy postać, obliczamy nową pozycjęj
, zapamiętujemy znak na pozycjij
, przypisujemy znaki
doj
i powtarzamy ze znakiem na indeksiej
. Ponieważ potrzebujemy informacji o spacji, aby obliczyć nową pozycję, koduję starą spację jako wielką wersję nowej litery, a nową spację jako „@”.źródło
length(string)/3
zmuszając każde słowo w najgorszym przypadku do co najmniej długości 2), wynik będzie mniejszy niż 2 (w powyższym przykładzie będzie to 1,67)if any(process_loop(...) for j in range(...))
Czy zadania z tych pętli procesowych nie powinny być liczone?dry_run
parametr jest ustawiony na niezerową (wartość nai
). Wewnątrzprocess_loop
, jeślidry_run
jest niezerowe, nie wykona żadnego przypisania.Perl, wynik 1,3̅
Dla każdego znaku spacji wykonywane jest jedno przypisanie, a dla każdego znaku spacji dwa przypisania.
Ponieważ znaki spacji nie mogą przekraczać połowy całkowitej liczby znaków, najgorszy wynik to 1,5 .Algorytm się nie zmienił, ale mogę udowodnić dolną górną granicę. Dokonajmy dwóch spostrzeżeń:
Można wtedy zobaczyć, że teoretyczny „najgorszy przypadek” z asymptotycznie 1/2 spacjami wcale nie jest najgorszy:
ab c d e f g h i ...
W rzeczywistości jest to całkiem niezły przypadek.
Aby zapobiec obserwacji pierwszego i drugiego powyżej, każde słowo składające się z jednego znaku musiałoby zostać umieszczone w środku słowa o długości trzech lub więcej znaków. Sugerowałoby to najgorszy przypadek zawierający asymptotycznie 1/3 spacji:
a bcd a bcd a ... bc
Lub równoważnie tylko słowa dwuznakowe:
a bc de fg hi jk ...
Ponieważ najgorszy przypadek zawiera asymptotycznie 1/3 spacji, najgorszy wynik wynosi 1,3̅ .
Edycja: Dodano licznik swapów i współczynnik.
Dane wejściowe są pobierane ze standardowego wejścia. Przykładowe użycie:
metoda
Aby rozpocząć, pierwszy znak ciągu zostaje przeniesiony do miejsca docelowego. Właśnie zastąpiona postać jest następnie przenoszona do miejsca docelowego itp. Trwa to do momentu spełnienia jednego z dwóch warunków:
Kiedy tak się dzieje, postać jest nie zamieniana z przestrzenią, ale raczej na pozycję lustrzaną przestrzeni. Algorytm kontynuuje od tej pozycji.
Gdy cel powróci do początkowej pozycji bieżącego cyklu, należy znaleźć następny niezmieniony znak (a raczej każdy niezamieniony znak). Aby to zrobić przy stałych ograniczeniach pamięci, wszystkie zamiany dokonane do tego momentu są śledzone wstecz.
Po tej fazie każda postać niebędąca spacją została przesunięta co najwyżej raz. Aby zakończyć, wszystkie znaki spacji są zamieniane na znaki w ich pozycjach lustrzanych, co wymaga dwóch operacji przypisania na spację.
źródło
Ruby, ocena 2
Na początek bardzo podstawowy algorytm. Najpierw odwraca cały ciąg, a następnie ponownie odwraca każde słowo w ciągu. W najgorszym przypadku (jedno słowo, parzysta liczba znaków) wynik wynosi 2.
Stosowanie:
źródło
C ++: wynik 2
źródło
Rebol
Nie jestem pewien co do punktacji w tym zakresie. W tym kodzie nie ma bezpośredniego przypisania ciągu. Wszystko jest obsługiwane przez ten,
reverse/part
który dokonuje cofania w miejscu wewnątrz i początkowo na całym łańcuchu.Niektóre szczegóły dotyczące kodu:
Pętlę przez string (
series
), aż dojdzie dotail?
Pierwszy raz w pętli wykonaj pełne odwrócenie łańcucha -
reverse/part series tail series
(który jest taki sam jakreverse series
)Następnie odwróć każde słowo znalezione w kolejnych iteracjach -
reverse/part series find series space
Gdy wyczerpane słowo znajdzie, następnie wróć,
tail series
aby odwrócić ostatnie słowo w ciągu -reverse/part series tail series
Rebol umożliwia przemierzanie łańcucha za pomocą wewnętrznego wskaźnika . Możesz to zobaczyć w
series: next f
(przesuń wskaźnik na za spacją, więc początek następnego słowa) iseries: head series
(resetuje wskaźnik z powrotem do głowy).Widzieć uzyskać więcej informacji, Seria .
Przykład użycia w konsoli Rebol:
źródło
C: Wynik 2
To tylko odwraca cały łańcuch, a następnie odwraca każde słowo.
źródło
Python: wynik 2
Prawie identyczny z algorytmem Howarda, ale wykonuje kroki odwrotne w odwrotnej kolejności (najpierw odwraca słowa, a następnie odwraca cały łańcuch). Dodatkowa pamięć stosuje się 3 zmienne bajt rozmiar:
i
,j
, it
. Techniczniefind
ilen
używają niektórych zmiennych wewnętrznych, ale równie dobrze mogłyby ponownie użyći
lubj
bez utraty funkcji.szybka edycja: zapisywanie przypisań ciągów poprzez zamianę tylko wtedy, gdy znaki się różnią, więc mogę zdobyć dodatkowe punkty z uwagi nr 2.
źródło
Partia
Przyznaję, że nie do końca rozumiem punktację (myślę, że to dwa) .. ale powiem - robi to .
Dane wejściowe są traktowane jako pierwsza standardowa wartość wejściowa, dlatego muszą być otoczone znakami cudzysłowu -
wywołanie:
script.bat "hello there everyone"
out:
everyone there hello
.Może ktoś inny może mnie zdobyć (zakładając, że nie zdyskwalifikowałem się w inny sposób).
źródło
JavaScript
Stosowanie:
Mam dziwne wrażenie, że coś przeoczyłem ...
źródło