Jak już wspomniano, problem ten jest podobny do bardziej znanego problemu edycji odległości (leżącego u podstaw odległości Levenshteina ). Ma również cechy wspólne, na przykład z odległością dynamicznego dopasowywania czasu (duplikacja lub „jąkanie się” w ostatnim wymaganiu).
Kroki w kierunku programowania dynamicznego
Moja pierwsza próba rekurencyjnego rozkładu wzdłuż linii Levenshteina i dynamicznej odległości wypaczania w czasie była podobna do następującej (dla i ), przy czym ustawiono
x=x1…xny=y1…ymd(x,y)
min⎧⎩⎨⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪⎪d(x,y1…ym−1)+1d(x,y2…ym)+1d(x,y1…ym/2)+1d(x1…xn/2,y)+1d(x1…xn,y)+1d(x1…xn−1,y1…ym−1)if y=y1…ym/2y1…ym/2if x=x1…xn/2x1…xn/2if yn=ym▻ Add letter at end▻ Add letter at beginning▻ Doubling▻ Halving▻ Deletion▻ Ignoring last elt.
Ostatnia opcja mówi tutaj, że konwersja FOOX na BARX jest równoważna konwersji FOOX na BAR. Oznacza to, że można użyć opcji „dodaj literę na końcu”, aby uzyskać efekt jąkania (powielania) i usuwanie w jednym punkcie. Problemem jest to, że automatycznie pozwala dodać dowolną postać w środku łańcucha , a także , co prawdopodobnie nie ma. (To „ignorowanie identycznych ostatnich elementów” jest standardowym sposobem na usunięcie i zacinanie się w dowolnych pozycjach. Uniemożliwia wprowadzanie dowolnych wstawek, jednocześnie pozwalając na dodawanie na obu końcach, choć trochę trudne…)
Zawarłem ten podział, nawet jeśli nie spełnia on całkowicie swojej funkcji, na wypadek, gdyby ktoś inny go „uratował” - i ponieważ używam go w moim heurystycznym rozwiązaniu, poniżej.
(Oczywiście, jeśli mógłbyś dostać taki podział, który faktycznie określał twój dystans, wystarczy dodać notatkę i mieć rozwiązanie. Jednak ponieważ nie pracujesz tylko z prefiksami, nie Pomyśl, że możesz użyć tylko indeksów do zapamiętywania; być może będziesz musiał przechowywać rzeczywiste, zmodyfikowane ciągi dla każdego połączenia, które byłyby ogromne, gdyby twoje ciągi były znacznej wielkości).
Kroki w kierunku rozwiązania heurystycznego
Innym podejściem, które może być łatwiejsze do zrozumienia i które mogłoby zająć nieco mniej miejsca, jest wyszukiwanie najkrótszej „ścieżki edycji” od pierwszego ciągu do drugiego za pomocą algorytmu (w zasadzie najlepiej - pierwszy odgałęziony). Przestrzeń wyszukiwania byłaby definiowana bezpośrednio przez twoje operacje edycji. Teraz, dla dużego łańcucha, zrobiłbyś toA∗uzyskać duże sąsiedztwo, ponieważ można usunąć dowolny znak (dając sąsiada dla każdego potencjalnego usunięcia) lub zduplikować dowolny znak (ponownie, dając liniową liczbę sąsiadów), a także dodać dowolny znak na każdym końcu, co by daje liczbę sąsiadów równą dwukrotności wielkości alfabetu. (Mam tylko nadzieję, że nie używasz pełnego Unicode ;-) Przy tak dużym fanoucie możesz osiągnąć całkiem spore przyspieszenie, używając dwukierunkowego lub jakiegoś krewnegoA∗ .
Aby działało, potrzebujesz dolnej granicy pozostałej odległości do celu. Nie jestem pewien, czy jest oczywistym wyborem tutaj, ale co mogła zrobić, to wdrożenie rozwiązania opartego na programowaniu dynamicznym rekurencyjnego rozkładu dałem powyżej (znowu z możliwych kwestiach kosmicznych jeśli struny są bardzo długie). Mimo, że rozkład nie dokładnie obliczyć dystans, to jest zagwarantowane dolną granicę (bo to jest bardziej liberalne), co oznacza, że będzie ona działać jako heurystyki w . (Jak ciasno będzie, nie wiem, ale byłoby poprawne.) Oczywiście zapamiętywanie funkcji powiązania może być współużytkowane we wszystkich obliczeniach granicy podczasA∗A∗A∗biegać. (Kompromis czasowy / kosmiczny.)
Więc…
Wydajność zaproponowanego przeze mnie rozwiązania wydaje się zależeć od (1) długości twoich ciągów i (2) od wielkości twojego alfabetu. Jeśli żadne z nich nie jest ogromne, może działać. To jest:
- Zaimplementuj dolną granicę odległości za pomocą mojego rekurencyjnego rozkładu i programowania dynamicznego (na przykład za pomocą zapamiętanej funkcji rekurencyjnej).
- Zaimplementuj (lub dwukierunkowy ) z operacjami edycji jako „ruchy” w przestrzeni stanów i dolną granicę opartą na programowaniu dynamicznym.A∗A∗
Naprawdę nie mogę dać żadnych gwarancji na to, jak efektywna byłaby, ale powinna być poprawna i prawdopodobnie byłaby o wiele lepsza niż rozwiązanie brutalnej siły.
Jeśli nic więcej, mam nadzieję, że daje to kilka pomysłów na dalsze badania.