Алгоритм відповідності рядків швидкого невідповідності


10

Я шукаю швидкий алгоритм відповідності рядків k-невідповідності. З огляду на рядок шаблону P довжиною m та текстовий рядок T довжиною n, мені потрібен швидкий (лінійний час) алгоритм, щоб знайти всі позиції, де P відповідає підрядку T з не більше k невідповідностей. Це відрізняється від проблеми k-відмінності (відстань редагування). Невідповідність має на увазі, що підрядок і візерунок мають різну букву в максимум k позиціях. Мені справді потрібна лише k = 1 (максимум 1 невідповідність), тому швидкого алгоритму для конкретного випадку k = 1 також буде достатньо. Розмір алфавіту становить 26 (нечутливий до регістру англійський текст), тому потреба в просторі не повинна зростати надто швидко з розміром алфавіту (наприклад, алгоритм FAAST, я вважаю, займає експоненціальний простір у розмірі алфавіту, і так підходить тільки для послідовностей білків і генів).

Підхід на основі динамічного програмування, як правило, буде O (mn) в гіршому випадку, який буде занадто повільним. Я вважаю, що для цього є модифікації алгоритму Бойєра-Мура, але я не в змозі взяти на себе такі документи. У мене немає підписки на доступ до академічних журналів чи публікацій, тому будь-які довідники повинні бути публічними.

Я дуже вдячний за будь-які вказівки або посилання на вільно доступні документи або сам алгоритм цієї проблеми.


2
Якщо шаблон є виправленим (але текст, який відповідає), потенційно ви можете створити обмежений автомат і запустити текст через нього. Існують також алгоритми, що використовують дерева суфіксів (як правило, добре, якщо текст є постійним і візерунок змінюється, але також застосовний, якщо обидва відрізняються), ви можете знайти деякі посилання в Інтернеті. (Ще не додаючи відповіді, оскільки я не дуже впевнений в алгоритмах на основі дерева суфіксів, якщо хтось знає, будь ласка, проігноруйте цей коментар).
Ар'ябхата

@Aryabhata Дякую! Змінюються і візерунок, і текст. У цьому контексті побудувати кінцевий автомат буде занадто дорого, особливо якщо включати область для 1 невідповідності. Щодо дерев суфіксів / суфіксівних масивів, я ніколи їх не використовував, і про них мало знаю, але мав враження, що вони повільно будують та ефективні в основному для точного узгодження. Але я вивчу цей варіант далі. Будь-які покажчики в цьому напрямку чи в будь-якому іншому напрямку були б найкориснішими!
Paresh

1
Ні, дерева суфіксів можуть використовуватися і для приблизних збігів. Принаймні, у вікі стверджується так: en.wikipedia.org/wiki/Suffix_tree
Aryabhata

Відповіді:


5

Для цієї проблеми можна використовувати масиви суфіксів . Вони містять вихідні положення кожного суфікса рядка, відсортованого в лексикографічному порядку. Незважаючи на те, що вони можуть бути побудовані по наївності в складності, є методи , щоб побудувати їх в thetas ; ( п ) складності. Дивіться, наприклад, це і це . Назвемо цей масив суфіксів SA.О(нжурналн)Θ(н)

Після створення суфіксного масиву нам потрібно побудувати найдовший масив загального префікса (LCP) для масиву суфіксів. Масив LCP зберігає довжину найдовшого загального префікса між двома послідовними префіксами в масиві суфіксів (лексикографічні послідовні суфікси). Таким чином, LCP [i] містить довжину найдовшого загального префікса між SA [i] та SA [i + 1]. Цей масив також може бути побудований у лінійному часі: дивіться тут , тут і тут кілька хороших посилань.

Тепер, щоб обчислити довжину найдовшого префікса, спільного для будь-яких двох суфіксів у дереві суфіксів (замість послідовних суфіксів), нам потрібно використовувати деяку структуру даних RMQ . У наведених вище посиланнях було показано (і їх можна легко побачити, якщо масив візуалізується як суфіксне дерево), що довжина найдовшого загального префікса між двома суфіксами, що мають позиції і v ( u < v ) у масиві суфіксів , може бути отримано як m i n u < = k < = v - 1 L C P [ k ]уvу<vмiну<=к<=v-1LСП[к]. Хороший RMQ може попередньо обробити масив за час O ( n ) або O ( n log n ) та відповісти на запити форми L C P [ u , v ] в O ( 1 ) час. Дивіться тут про алгоритм стислих RMQ, а тут - хороший підручник з питань RMQ та взаємозв'язку (та скорочень) між LCA та RMQ. Це ще один приємний альтернативний підхід.LСПО(н)О(нжурналн)LСП[у,v]О(1)

За допомогою цієї інформації ми будуємо суфіксний масив та пов’язані з ними масиви (як описано вище) для конкатенації двох рядків з роздільником між ними (наприклад, T # P, де "#" не зустрічається в жодному рядку). Тоді ми можемо виконати збіг рядків k невідповідності за допомогою методу "кенгуру". Це і це пояснює метод кенгуру в контексті дерев суфіксів, але він може бути безпосередньо застосований і до масивів суфіксів. Для кожного індексу тексту T знайдіть L C P суфікса T, що починається з i, і суфікса PiТLСПТiПпочинаючи з 0. Це дає місце, після якого виникає перше невідповідність при зіставленні з T [ i ] . Нехай ця довжина буде l 0 . Пропустіть невідповідний символ як у T, так і в P і спробуйте відповідати решти рядків. Тобто, знову - таки знаходимо л З Р з Т [ я + л 0 + 1 ] і Р [ л 0 + 1 ] . Повторіть це, доки не отримаєте k невідповідностей або завершення рядків. КоженПТ[i]л0ТПLСПТ[i+л0+1]П[л0+1]к є O ( 1 ) . Є O ( K ) L З Р «S для кожного індексу я з T , даючи це загальна складність O ( п до ) .LСПО(1)О(к) LСПiТО(нк)

Я використав простіший для реалізації RMQ, що дає загальну складність , або O ( n k + n log n ), якщо m = O ( n ) , але це можна також виконати в O ( n k ), як описано вище. Для цієї проблеми можуть бути й інші прямі методи, але це потужний і загальний підхід, який можна застосувати до багатьох подібних проблем.О(нк+(н+м)журнал(н+м))О(нк+нжурналн)м=О(н)О(нк)


Чудово! Зараз у своєму списку TODO я читаю :-)
Ар'ябхата

Посилання siam.org у другому абзаці розірвано, але зв'язаний папір можна знайти тут epubs.siam.org/doi/pdf/10.1137/1.9781611972917.3
leecbaker

4

Нижче наведено очікуваний алгоритм (який можна поширити на інші k , зробивши його O ( n k + m ) ). (Я не робив розрахунків, щоб довести, що це так).O(n+m)кO(нк+м)

Ідея схожа на алгоритм хеш-катування Rabin-Karp для точних збігів підрядків.

Ідея полягає в тому, щоб відокремити кожен рядок довжини в 2 - K блоків м / 2 до розміру кожного , і обчислити коченню хеш для кожного блоку (дає 2 до хеш - значення) і порівняти ці 2 K хеш - значення по відношенню до одного з шаблону.м2км/2к2к2к

У цих значеннях ми допускаємо не більше невідповідностей.к

Якщо трапляється більше невідповідностей, ми відхиляємось і рухаємось далі. В іншому випадку ми намагаємося підтвердити приблизну відповідність.к

Я очікую (застереження: я сам не пробував) це, мабуть, буде швидше на практиці і, можливо, простіше кодувати / підтримувати, ніж використовувати підхід на основі дерева суфіксів.


Просто потрібне уточнення. Під "..розділіть кожен рядок довжиною m на 2k блоки розміром m / 2k кожен ...", ви маєте на увазі, що розділіть кожну підрядку довжиною m в T (довжиною n) на 2k блоки. І цей хеш може бути обчислений в O (n) методом прокатки хешу. Тоді рядок шаблону також буде розділена на 2k блоки, і відповідні хеші порівнятимуться, даючи припущення невідповідності принаймні k блоків. Якщо так, то ми могли б відмовитися від усіх випадків, коли кількість невідповідностей перевищує k. Я правильно зрозумів?
Paresh

кΩ(нк)О(н)

Мені подобається такий підхід! Тим не менш, цей підхід в цілому швидкий, але погіршується до O (mnk), якщо кількість збігів висока (O (n) збігів). Маючи це на увазі, я підтримував два хешируючих кочення, припускаючи, що обидва не можуть мати зіткнення для одного входу (я цього не робив математично, оскільки хотів побачити швидкість). Таким чином, нам не доведеться перевіряти відповідність, якщо два хеши погоджуються. Загалом це досить швидко, але це теж повільно, якщо кількість матчів велика. З цим і з тим, як ви запропонували, для великих матчів це було повільно.
Пареш

мм/2кмО(нкм)

мм/2к2кк+1к+cΩ(нм)мм/2к
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.