W przypadku narzędzia wyszukiwania po stronie klienta muszę znaleźć odległość Levenshteina słowa z milionami innych słów. Użytkownik powinien mieć możliwość porównania krótkiego tekstu około dwudziestu słów z książką. Użytkownik może to zrobić, znajdując lokalizacje najbardziej charakterystycznych słów tekstu w książce. "Szukanie lokalizacji" nie oznacza szukania dokładnego dopasowania, ale prawie identyczne jak z levenshtein. Zacząłem od już dostępnych wdrożeń, ale potrzebowałem większej prędkości. Skończyło się tak:Jaki jest najszybszy algorytm algorytmu dla szerokiego zastosowania
var rowA = new Uint16Array(1e6);
var rowB = new Uint16Array(1e6);
function levenshtein(s1, s2) {
var s1_len = s1.length, s2_len = s2.length, i1, i2 = 0, a, b, c, c2, i = 0;
if (s1_len === 0)
return s2_len;
if (s2_len === 0)
return s1_len;
while (i < s1_len)
rowA[i] = ++i;
while (i2 < s2_len) {
c2 = s2[i2];
a = i2;
++i2;
b = i2;
for (i1 = 0; i1 < s1_len; ++i1) {
c = a + (s1[i1] !== c2);
a = rowA[i1];
b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
rowB[i1] = b;
}
if (i2 === s2_len)
return b;
c2 = s2[i2];
a = i2;
++i2;
b = i2;
for (i1 = 0; i1 < s1_len; ++i1) {
c = a + (s1[i1] !== c2);
a = rowB[i1];
b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
rowA[i1] = b;
}
}
return b;
}
Jak widać użyłem techniki jak umieszczenie obiektów z funkcji w celu ponownego ich używać. Powtórzyłem też trochę przez linearyzację pętli. Czy to może być szybciej? Jestem ciekaw twojej rady.
Aktualizacja: Po wskazówki od Bergi i trochę więcej myślenia doszedłem do tego rozwiązania:
var row = new Uint16Array(1e6);
function levenshtein(s1, s2) {
var s1_len = s1.length, s2_len = s2.length, i2 = 1, a, b = 0, c, c2, i1 = 0;
if (s1_len === 0)
return s2_len;
if (s2_len === 0)
return s1_len;
c2 = s2[0];
if (s1[0] === c2) {
while (i1 < s1_len) {
row[i1] = i1++;
}
b = s1_len - 1;
} else {
row[0] = 1;
++b;
if (s1_len > 1)
for (i1 = 1; i1 < s1_len; ++i1) {
if (s1[i1] === c2) {
row[i1] = b;
for (++i1; i1 < s1_len; ++i1) {
row[i1] = ++b;
}
} else {
row[i1] = ++b;
}
}
}
if (s2_len > 1)
while (i2 < s2_len) {
c2 = s2[i2];
c = i2 + (s1[0] !== c2);
a = row[0];
++i2;
b = i2 < a ? (i2 < c ? i2 + 1 : c) : (a < c ? a + 1 : c);
row[0] = b;
if (s1_len > 1) {
for (i1 = 1; i1 < s1_len; ++i1) {
c = a + (s1[i1] !== c2);
a = row[i1];
b = b < a ? (b < c ? b + 1 : c) : (a < c ? a + 1 : c);
row[i1] = b;
}
}
}
return b;
}
To znowu znacznie szybciej. Nie mogę wycisnąć z tego więcej. Wciąż szukam innych pomysłów i spróbuję czegoś więcej.
Czy znasz ten wątek: http://stackoverflow.com/questions/11919065/sort-an-array-by-the-levenshtein-distance-with-estestance-in-javascript? –
Tak, jestem, ale levDist ("wiedza", "skonfigurowany") daje mi 8, podczas gdy oczekiwałem 9. Nie jestem tego pewien. –
@MarcodeWit: Komentarze na temat zaakceptowanej odpowiedzi wyjaśniają, że kod zawiera Damerau-Levensthein, który daje 8 słów. – Bergi