Pracuję nad implementacją wyszukiwania rozmytego i jako część implementacji używamy StringUtils.getLevenshteinDistance Apache. W tej chwili szukamy konkretnego maksymalnego średniego czasu odpowiedzi dla naszego wyszukiwania rozmytego. Po różnych ulepszeniach i pewnym profilowaniu miejscem, w którym spędza się najwięcej czasu, jest obliczenie odległości Levenshteina. Zajmuje około 80-90% całkowitego czasu wyszukiwania trzech liter lub więcej.Modyfikowanie algorytmu Levenshtein Distance, aby nie obliczyć wszystkich odległości
Wiem, że są pewne ograniczenia co do tego, co można tutaj zrobić, ale czytałem na poprzednich pytaniach SO i na linku do Wikipedii dla LD, że jeśli ktoś chce ograniczyć próg do ustalonej maksymalnej odległości, to może pomóc w ograniczeniu czasu spędzonego na algorytmie, ale nie jestem pewien, jak to zrobić dokładnie.
Jeśli jesteśmy zainteresowani tylko w odległości do jeżeli jest ona mniejsza niż progowej k, to wystarczy obliczyć przekątnej paskiem o szerokości 2k + 1 w matrycy. W ten sposób algorytm może być uruchamiany w czasie O (kl), , gdzie l jest długością najkrótszego ciągu . [3]
Poniżej zostanie wyświetlony oryginalny kod LH z StringUtils. Po tym jest moja modyfikacja. Próbuję w zasadzie obliczyć odległości o zadanej długości od przekątnej i, j (tak, w moim przykładzie, dwie przekątne powyżej i poniżej przekątnej i, j). Jednak nie może to być poprawne, tak jak to zrobiłem. Na przykład na najwyższej przekątnej zawsze wybierze wartość komórki bezpośrednio powyżej, która będzie wynosić 0. Jeśli ktoś mógłby mi pokazać, jak sprawić, by działało to tak, jak opisałem, lub ogólną radę, jak to zmienić , byłoby to bardzo docenione.
public static int getLevenshteinDistance(String s, String t) {
if (s == null || t == null) {
throw new IllegalArgumentException("Strings must not be null");
}
int n = s.length(); // length of s
int m = t.length(); // length of t
if (n == 0) {
return m;
} else if (m == 0) {
return n;
}
if (n > m) {
// swap the input strings to consume less memory
String tmp = s;
s = t;
t = tmp;
n = m;
m = t.length();
}
int p[] = new int[n+1]; //'previous' cost array, horizontally
int d[] = new int[n+1]; // cost array, horizontally
int _d[]; //placeholder to assist in swapping p and d
// indexes into strings s and t
int i; // iterates through s
int j; // iterates through t
char t_j; // jth character of t
int cost; // cost
for (i = 0; i<=n; i++) {
p[i] = i;
}
for (j = 1; j<=m; j++) {
t_j = t.charAt(j-1);
d[0] = j;
for (i=1; i<=n; i++) {
cost = s.charAt(i-1)==t_j ? 0 : 1;
// minimum of cell to the left+1, to the top+1, diagonally left and up +cost
d[i] = Math.min(Math.min(d[i-1]+1, p[i]+1), p[i-1]+cost);
}
// copy current distance counts to 'previous row' distance counts
_d = p;
p = d;
d = _d;
}
// our last action in the above loop was to switch d and p, so p now
// actually has the most recent cost counts
return p[n];
}
Moje modyfikacje (tylko do pętli):
for (j = 1; j<=m; j++) {
t_j = t.charAt(j-1);
d[0] = j;
int k = Math.max(j-2, 1);
for (i = k; i <= Math.min(j+2, n); i++) {
cost = s.charAt(i-1)==t_j ? 0 : 1;
// minimum of cell to the left+1, to the top+1, diagonally left and up +cost
d[i] = Math.min(Math.min(d[i-1]+1, p[i]+1), p[i-1]+cost);
}
// copy current distance counts to 'previous row' distance counts
_d = p;
p = d;
d = _d;
}
Myśl tylko przyszło mi do głowy, że mogę sprawdzić, czy wartość jest równa zero a następnie zignoruj ją lub zastąp ją dowolnie wysoką wartością. Może jednak pomyśleć o tym trochę więcej. – AHungerArtist