Odległość edycji (lub Levenshteina) między dwoma łańcuchami to minimalna liczba wstawek, usunięć i podstawień pojedynczych znaków potrzebnych do przekształcenia jednego łańcucha w drugi. Jeżeli oba ciągi mają długość n, dobrze wiadomo, że można to zrobić w czasie O (n ^ 2) przez programowanie dynamiczne. Poniższy kod Python wykonuje te obliczenia dla dwóch łańcuchów s1
i s2
.
def edit_distance(s1, s2):
l1 = len(s1)
l2 = len(s2)
matrix = [range(l1 + 1)] * (l2 + 1)
for zz in range(l2 + 1):
matrix[zz] = range(zz,zz + l1 + 1)
for zz in range(0,l2):
for sz in range(0,l1):
if s1[sz] == s2[zz]:
matrix[zz+1][sz+1] = min(matrix[zz+1][sz] + 1, matrix[zz][sz+1] + 1, matrix[zz][sz])
else:
matrix[zz+1][sz+1] = min(matrix[zz+1][sz] + 1, matrix[zz][sz+1] + 1, matrix[zz][sz] + 1)
return matrix[l2][l1]
W tym zadaniu musisz być jak najbliżej obliczenia odległości edycji, ale z poważnym ograniczeniem pamięci. Twój kod może zdefiniować jedną tablicę zawierającą 1000 32-bitowych liczb całkowitych i ma to być jedyna tymczasowa pamięć używana w obliczeniach. Wszystkie zmienne i struktury danych muszą być zawarte w tej tablicy. W szczególności nie można zaimplementować powyższego algorytmu, jak w przypadku ciągów o długości 1000, ponieważ wymagałoby to przechowywania co najmniej 1 000 000 liczb. Tam, gdzie twój język nie ma naturalnie 32-bitowych liczb całkowitych (na przykład Python), musisz po prostu upewnić się, że nigdy nie przechowujesz w tablicy liczby większej niż 2 ^ 32-1.
Możesz odczytywać dane przy użyciu dowolnej standardowej biblioteki, którą wybierzesz, bez obawy o ograniczenia pamięci w tej części. Aby konkurs był sprawiedliwy dla głównej części kodu, możesz używać tylko operacji, które są funkcjonalnie równoważne z operacjami w języku programowania C i nie możesz używać żadnych zewnętrznych bibliotek.
Aby być bardziej przejrzystym, pamięć do przechowywania danych wejściowych lub używana przez tłumacza języka, JVM itp. Nie wlicza się do limitu i nie możesz nic zapisywać na dysku. Musisz założyć, że dane wejściowe są tylko do odczytu, gdy znajdują się w pamięci, więc nie możesz ich ponownie użyć, aby uzyskać więcej miejsca do pracy.
Co muszę wdrożyć?
Twój kod powinien zostać odczytany w pliku w następującym formacie. Będzie miał trzy linie. Pierwszy wiersz to prawdziwa odległość edycji. Drugi to ciąg 1, a trzeci to ciąg 2. Przetestuję go z przykładowymi danymi na stronie https://bpaste.net/show/6905001d52e8, gdzie ciągi mają długość 10 000, ale nie powinno się specjalizować dla tych danych. Powinien generować najmniejszą możliwą odległość edycji między dwoma ciągami.
Będziesz także musiał udowodnić, że odległość do edycji faktycznie pochodzi od prawidłowego zestawu zmian. Twój kod powinien mieć przełącznik, który zmienia go w tryb, który może zużywać więcej pamięci (tyle, ile chcesz) i wyświetla operacje edycji, które dają odległość do edycji.
Wynik
Twój wynik będzie (optimal edit distance/divided by the edit distance you find) * 100
. Na początek zauważ, że możesz uzyskać wynik, po prostu licząc liczbę niedopasowań między dwoma ciągami.
Możesz używać dowolnego języka, który ci się podoba, który jest swobodnie dostępny i łatwy do zainstalowania w systemie Linux.
Tie break
W przypadku remisu uruchomię twój kod na moim komputerze z systemem Linux i najszybszy kod wygrywa.
{ uint32_t foo[1000]; for (foo[0] = 0; foo[0] < 5; ++foo[0]) printf("%d ", foo[0]); }
Zakładamy, że twoja tablica 32-bitowych liczb całkowitych zostanie wywołana foo
.
for(int i=0;i<=5;i++)
dozwolone, ponieważ przechowuje danei
?