Орієнтовна початкова точка пошуку рядків - відстань Левенштейна . Цей алгоритм підраховує кількість редагувань одного символу (вставлення, видалення та заміна) для зміни одного слова на інше.
Прикладом цього є kitten
-> sitting
який має відстань редагування три
- k itten -> s itten (замінити 's' на 'k')
- sitt e n -> sitt i n (замінити 'i' на 'e')
- sittin -> sittin g (в кінці додайте 'g')
У цьому алгоритмі існують різні варіанти, зокрема відстань Дамерау - Левенштейн, яка дозволяє переносити два суміжних символи ("hte" до "the" має відстань DL 1 і відстань Левенштейна 2), і тому часто більше підходить для перевірка орфографії. Інші варіанти існують для додатків, де важливі прогалини (рядки ДНК).
Відстань Левенштейна добре відома і не надто складна для пошуку (мені колись довелося переслідувати її реалізацію як функцію в Oracle - це було набагато швидше, ніж витягувати всі дані і потім запускати сторону коду запиту). Розеттакод має безліч (54) реалізацій відстані Левенштейна (зауважте, що деякі мови мають десь частину бібліотеки струн - якщо ви робите Java, подивіться на apache commons lang ). Wikibooks має 31 реалізацію, і короткий погляд на два не показує однаковий код для тієї самої мови.
Як це працює, це будує матрицю, яка відповідає взаємозв'язку між двома рядками:
.kitten
.0123456
s1123456
i2212345
t3321234
t4432123
i5543223
n6654332
g7765443
.
Рядків і стовпців представляють , що ви можете отримати в цільової рядку по «просто» вставити кожну букву з порожнього рядка. Це не ідеальний випадок, але він існує для виведення алгоритму.
Якщо значення збігається з точкою ('i' == 'i'), значення те саме, що значення діагонально вліво зліва. Якщо дві плями відрізняються ('s'! = 'K'), значення є мінімальним:
- по діагоналі вліво та вліво + 1 (заміна)
- безпосередньо над + 1 (вставка)
- безпосередньо вліво + 1 (видалення)
Значення повернення відстані редагування - це значення в нижньому правому куті матриці.
Якщо слідувати з правого нижнього правого верхнього лівого кута з мінімумом, ви можете побачити зроблені зміни:
.kitten
.0. .
s.1 .
i 1 .
t 1 .
t 1.
i.....2
n 2
g......3
Зауважте, що це досить інтенсивний пам'ять. Це може бути зменшено в області пам’яті, не будуючи повну матрицю - весь алгоритм, який піклується, - це підмножина даних, і його можна зменшити з N*M
простору в 2*max(N,M)
простір, просто зберігаючи попередній рядок (і те, що було обчислено за поточним ряд). Проект Code показує, як це можна зробити (з завантаженням коду C #).