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.
for(int i=0;i<=5;i++)
dozwolone, ponieważ przechowuje danei
?{ 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łanafoo
.Odpowiedzi:
C ++, wynik 92,35
Algorytm szacowania: Algorytm znajduje pierwsze miejsce, w którym różnią się dwa ciągi, a następnie wypróbowuje wszystkie możliwe permutacje operacji N (wstawianie, usuwanie, zamiana - pasujące znaki są pomijane bez wykonywania operacji). Wylicza każdy możliwy zestaw operacji na podstawie tego, o ile dalej ten zestaw operacji z powodzeniem dopasowuje dwa łańcuchy, a także na ile powoduje, że długości łańcuchów się zbiegają. Po określeniu zestawu N operacji o najwyższym wyniku, stosowana jest pierwsza operacja w zestawie, odnajdowane jest kolejne niedopasowanie, a proces jest powtarzany aż do osiągnięcia końca łańcucha.
Program wypróbowuje wszystkie wartości N od 1-10 i wybiera poziom, który dał najlepsze wyniki. N = 10 jest na ogół najlepszy teraz, gdy metoda punktacji uwzględnia długość struny. Wyższe wartości N byłyby prawdopodobnie jeszcze lepsze, ale zajmują wykładniczo więcej czasu.
Użycie pamięci: Ponieważ program jest wyłącznie iteracyjny, potrzebuje bardzo mało pamięci. Tylko 19 zmiennych jest używanych do śledzenia stanu programu. Są one ustawiane przez # definicje, aby działać jak zmienne globalne.
Użycie: Program jest używany tak samo jak feersum: pierwszy parametr jest uważany za plik, a wszelkie dodatkowe parametry wskazują, że zmiany powinny być pokazane. Program zawsze drukuje szacunkową odległość edycji i wynik.
Dane wyjściowe z weryfikacji: dane wyjściowe z weryfikacji sformatowano w trzech wierszach:
Górny rząd to ciąg docelowy, środkowy to operacje, a dolny to edytowany ciąg. Spacje w wierszu operacji wskazują, że znaki są zgodne. „R” oznacza, że łańcuch edycji ma znak w tej pozycji zastąpiony znakiem łańcucha docelowego. „I” oznacza, że w łańcuchu edycji wstawiono znak łańcucha docelowego w tej pozycji. „D” oznacza, że ciąg znaków edycji ma usunięty znak w tej pozycji. Ciągi edycji i docelowe mają spacje wstawiane, gdy drugi ma znak wstawiony lub usunięty, więc są wyrównane.
źródło
C ++ 75.0
Program przeznaczony jest do pracy z dowolnymi ciągami tekstowymi. Mogą mieć dowolną długość, o ile żadna z nich nie przekracza 13824 znaków. Używa 1897 16-bitowych liczb całkowitych, co odpowiada 949 32-bitowych liczb całkowitych. Na początku pisałem w C, ale potem zdałem sobie sprawę, że nie ma funkcji do czytania linii.
Pierwszym argumentem wiersza polecenia powinna być nazwa pliku. Jeśli istnieje drugi argument, drukowane jest podsumowanie zmian. Pierwszy wiersz w pliku jest ignorowany, a drugi i trzeci to ciągi znaków.
Algorytm jest podwójnie zablokowaną wersją zwykłego algorytmu. Wykonuje w zasadzie tę samą liczbę operacji, ale jest oczywiście znacznie mniej dokładny, ponieważ jeśli wspólna podsekwencja zostanie podzielona na krawędź bloku, wiele potencjalnych oszczędności zostanie utraconych.
źródło
Python,
100Udało mi się idealnie wyliczyć odległość edycji w przydzielonym limicie pamięci. Niestety, ten wpis narusza dwie zasady wyzwania, w piśmie, jeśli nie w duchu.
Po pierwsze, tak naprawdę nie zapisałem moich danych w 1000 32-bitowych liczbach całkowitych. Dla ciągów o długości 10000 znaków mój program tworzy dwie tablice o długości 10000 elementów, które będą zawierały tylko +1, 0 lub -1. Przy 1,585 bitów na liczbę trójskładnikową byłoby możliwe spakowanie tych 20000 tritów w 31700 bitów, pozostawiając 300 bitów jako więcej niż wystarczającą ilość dla moich 7 pozostałych 16-bitowych liczb całkowitych.
Po drugie, nie wdrożyłem wymaganego trybu wyświetlania zmian. Alternatywnie zaimplementowałem tryb, który drukuje pełną matrycę edycji. Jest absolutnie możliwe obliczenie ścieżki edycji na podstawie tej matrycy, ale nie mam teraz czasu na jej wdrożenie.
przykładowe dane wejściowe:
przykładowe pełne dane wyjściowe:
źródło