Алгоритм Ландау-Вишкина (k несовпадений) — различия между версиями
Margarita (обсуждение | вклад) (→Процедура merge) |
Margarita (обсуждение | вклад) (→Оценка работы) |
||
| Строка 146: | Строка 146: | ||
Рассмотрим построение <tex>pm</tex>Используя аргументы, аналогичные применявшимся при проверке корректности процедуры merge, можно показать, что для нахождения требуемого количества несовпадений на стадии s требуется <tex>min\{2^{log(m)-s}4k+1, m-2^{s}\}</tex> позиций, для которых выполняется условие B, и в особом случае, а именно, на стадии <tex>\log m</tex>, требуется <tex>4k + 1</tex> таких позиций. | Рассмотрим построение <tex>pm</tex>Используя аргументы, аналогичные применявшимся при проверке корректности процедуры merge, можно показать, что для нахождения требуемого количества несовпадений на стадии s требуется <tex>min\{2^{log(m)-s}4k+1, m-2^{s}\}</tex> позиций, для которых выполняется условие B, и в особом случае, а именно, на стадии <tex>\log m</tex>, требуется <tex>4k + 1</tex> таких позиций. | ||
| − | На каждой стадии <tex>s</tex> из <tex>\log m</tex> стадий анализа образца цикл <tex>for</tex> производит <tex>2^{s-1}</tex> итераций <tex>(2^{s-1} \leqslant i \leqslant 2^{s}-1)</tex>. Если не считать время работы процедур <tex>merge</tex> и <tex>extend</tex>, каждая итерация требует фиксированного времени. Для всех итераций на шаге <tex>s</tex> процедуре <tex>extend</tex> требуется время <tex>O(m)</tex>. Ранее было показано, что время работы <tex>merge</tex> пропорционально числу искомых несовпадений. Таким образом, каждый вызов <tex>merge</tex> занимает время <tex>O(min\{2^{log(m)-s}4k+1, m-2^{s}\})</tex>, что равно <tex>O(2k2^{\log (m-s)})</tex>. Таким образом, общее время для стадии <tex>s</tex> равно <tex>O(m+2^{l-1}(2k2^{\log (m-s)}))</tex> = <tex>O(km)</tex>. Проведя суммирование по всем стадиям, получаем общее время счета (// | + | На каждой стадии <tex>s</tex> из <tex>\log m</tex> стадий анализа образца цикл <tex>for</tex> производит <tex>2^{s-1}</tex> итераций <tex>(2^{s-1} \leqslant i \leqslant 2^{s}-1)</tex>. Если не считать время работы процедур <tex>merge</tex> и <tex>extend</tex>, каждая итерация требует фиксированного времени. Для всех итераций на шаге <tex>s</tex> процедуре <tex>extend</tex> требуется время <tex>O(m)</tex>. Ранее было показано, что время работы <tex>merge</tex> пропорционально числу искомых несовпадений. Таким образом, каждый вызов <tex>merge</tex> занимает время <tex>O(min\{2^{log(m)-s}4k+1, m-2^{s}\})</tex>, что равно <tex>O(2k2^{\log (m-s)})</tex>. Таким образом, общее время для стадии <tex>s</tex> равно <tex>O(m+2^{l-1}(2k2^{\log (m-s)}))</tex> = <tex>O(km)</tex>. Проведя суммирование по всем стадиям, получаем общее время счета <tex>O(\sum_{i=1}^{\log m} km)</tex> = <tex>O(km \log m)</tex>. Таким образом, общие затраты времени, включающие предварительную обработку образца и анализ текста, равны <tex>O(k(n + m \log m))</tex>. |
=Пример= | =Пример= | ||
Версия 18:42, 16 июня 2014
Постановка задачи: Дано число текст и образец , . Требуется найти все подстроки текста длины , с не более чем несовпадающими символами с образцом. Эту задачу решает алгоритм Ландау-Вишкина (k несовпадений) (англ.Landau-Vishkin Algorithm)
Содержание
Алгоритм
Идея
При анализе используется двумерный массив несовпадений текста , содержащий информацию о несовпадениях текста с образцом. По завершении анализа в его -й строке содержатся позиции в первых несовпадений между строками и . Таким образом, если , то , и это -е несовпадение между и , считая слева направо. Если число несовпадений с подстрокой меньше , то, начиная с , элементы -й строки равны значению по умолчанию .
Заметим, если , то подстрока отличается от образца не более, чем на символов, и, таким образом, является решением задачи.
Затем образец сканируется параллельно с текстом слева на права по одному символу за раз. На итерации с образцом сравнивается подстрока . - обозначим самую правую позицию в тексте, достигнутую за предыдущие итерации, то есть является максимальным из чисел , где . Если , в присваивается результат работы , которая находит количество несовпадений между и . Если не превышает , вызывается процедура , которая сравнивает подстроки и , где изменяется таблица текстовых несовпадений. Переменная будет рассмотренна ниже.
|
tm[0...n-m][1...k+1] = m+1 // инициализация
r = 0
j = 0
for i = 0 to n - m
b = 0
if i < j
b = merge(i, r, j)
if b < k + 1
r = i
extend(i, j, b)
|
Процедура extend
Рассмотрим процедуру подробнее. Она сравнивает подстроки и , в случае несовпадения увеличивается и таблица текстовых несовпадений обновляется. Это происходит пока либо не будет найдено несовпадений (учитывая несовпадения, которые были найдены раньше на -ой итерации), либо не будет достигнуто с не больше чем несовпадениями, то есть найдено вхождение образца, начинающееся с .
|
extend(i, j, b)
while (b < k + 1) and (j - i < m)
j++
if y[j] != x[j-1]
b++
tm[i][b] = j - i
|
Процедура merge
Рассмотрим процедуру подробнее. Она находит количество несовпадений между и и устанавливает b равным найденному числу, при этом используется полученая ранее информация. Введем - это строка таблицы несовпадений, в которой есть информация о несовпадениях, полученных при совмещении начала образца и . содержит текущий номер самой правой из проверенных на настоящий момент позиций текста. Поэтому при обработки построки начинающейся с , можно учитывать информацию в -ой строке , которая содержит информацию о сопоставлении образца с . Подходящими значениями из таблицы несовпадений являются, таким образом, , где – это наименьшее из целых чисел, для которых . Однако, следует учитывать тот факт, что эти несовпадения соответствуют началу образца, выравниваемому с , в то время как текущая позиция образца выровнена с – разница в мест.
Также в алгоритме используется двумерный массив несовпадений образца , генерируемой на стадии предварительной обработки образца. В нем содержатся позиции несовпадения образца с самим собой при различных сдвигах, аналогично , то есть в -ой строке содержитатся позиции внутри первых несовпадений между подстроками и . Таким образом, если , то , и это -е несовпадение между и слева направо. Если число несовпадений между этими строками меньше , то, начиная с , элементы -й строки равны , значению по умолчанию. Построение будет подробнее рассмотренно позднее.
Таким образом, для интерес представляет строка таблицы несовпадений образца, причем используются значения , где – самое правое несовпадение в , такое, что , так как требуются только несовпадения в подстроке .
Чтобы использовать упомянутую информацию в процедуре , рассмотрим в тексте позицию , находящуюся в диапазоне, //todo. Рассмотрим следующие условия для позиции :
Условие A: когда символы и совмещены, позиция в тексте соответствует предварительно выявленному несовпадению между образцом и текстом, то есть , и это несовпадение номер , где , то есть .
Условие B: для двух копий образца, со сдвигом относительно друг друга , совмещенных с текстом так, что их начальные символы лежат, соответственно, над и , позиция соответствует несовпадению между двумя образцам, то есть . Это -е несовпадение при этом сдвиге, где , то есть = .
Вспомним, что нас интересует, совпадает ли символ текста в позиции с соответствующими символом образца, когда совмещен с , то есть верно ли, что . Рассмотрим этот вопрос при разных комбинациях указанных выше условий.
Случай 1: !A and !B: То есть, и , откуда . Нет необходимости сравнивать символ текста с символом образца, так как ясно, что в этой позиции они совпадают.
Случай 2: (A and !B) or (!A and B): В любом случае (если лишь условие истинно, то и , откуда , с другой стороны, если выполнено только условие , то и , и опять, ). Как и в предыдущем случае, нет необходимости сравнивать символ текста с символом образца, так как известно, что они не совпадают.
Случай 3: A and B: В этом случае мы ничего не можем сказать о том, совпадают ли символы и , поэтому их надо сравнить.
Возвращаемся к процедуре merge. В случае 2, или если в случае 3 выявлено несовпадение символов, необходимо увеличить количество несовпадений символов на единицу и обновить . Соответствующими значениями таблицы для являются и . Переменные и в начале устанавливаются равными индексам первых элементов этих двух массовов, соответственно, и последовательно увеличиваются.
Условия окончания работы процедуры следующие:
- Eсли , то для случая, когда образц расположен относительно текста так, что совмещен с , обнаружено несовпадение, поэтому из процедуры можно выйти.
- Bспомним, что самая правая из интересующих нас позиций в , а именно, , равна , если , поэтому будет уже использовано для предыдущего значения , а именно, , и поэтому позиция должна быть пропущена. Следовательно, в этом случае также можно выйти из процедуры.
- Процедуру можно прервать, если и . Если выполняется вторая часть этого условия, то равняется , и соответствует суммам для последующих значений вплоть до . В этом случае процедура может быть прервана, если выполняется также первая часть приведенного условия, так как она указывает, что позиция текста фактически пропущена.
Остается показать, что число позиций несовпадений в таблице несовпадений образца достаточно для того, чтобы нашла все, или, если их больше , первые несовпадений для . Это можно показать следующим образом. Условие A выполняется не больше чем для позиции текста в диапазоне . Условие B выполняется для некоторого неизвестного числа позиций в этом же интервале. Строка в таблице несовпадений образца, , содержит не больше чем позиций несовпадений между двумя копиями образца, с соответствующим сдвигом . Если , то таблица содержит все позиции несовпадения образца самим с собой, у которых условие B выполняется для позиций текста в интервале . С другой стороны, если , то таблица может дать позиций текста в диапазоне , для которых выполняется условие B. Поскольку , в диапазоне имеется до позиций текста, для которых выполняется условие A. Таким образом, в худшем случае может быть позиций, для которых имеет место случай 3, и которые требуется сравнить напрямую. Остается по крайней мере позиций, удовлетворяющих условию B, но не условию A (случай 2), что является достаточным, чтобы заключить, что для данного положения образца относительно текста имеется не меньше несовпадений между текстом и образцом.
|
merge(i, r, j, b)
u = 1
v = q
while (b < k + 1) and (v < k + 2) and (i + pm[i - r][u] < j or tm[r][v] != m + 1)
if i + pm[i - r][u] > r + tm[r][v] // Случай 2, условие A
b++
tm[i][b] = tm[r][v] - (i - r)
v++
else if i + pm[i - r][u] < r + tm[r, v] // Случай 2, условие B
b++
tm[i][b] = pm[i - r][u]
u++
else // Случай 3
I + PM[I - R, U] = R + TM[R, V]
if x[ pm[i-r][u] ] != y[ i+pm[i-r][u] ]
b++
tm[i][b] = pm[i - r][u]
u++
v++
|
Построение pm
Теперь осталось только обратиться к вычислению таблицы несовпадений шаблона на стадии предварительных вычислений. Не теряя общности, можно предположить, что является некоторой степенью . В алгоритме предварительной обработки используется разбиение множества из строк на следующие подмножеств:
Алгоритм состоит из этапов. На этапе , где , вычисляются строки в множестве , где множество – это .
Метод, используемый для вычисления этой таблицы, основан на методе, используемом на стадии анализа текста. Рассмотрим алгоритм для этапа . На стадии входами для алгоритма анализа образца являются подстроки образца и , которые трактуются здесь, соответственно, как образец и текст, и массив , содержащий выходы предыдущих стадий. (Число элементов в строках подмассива будет объяснено позже). Выходы стадии вводятся в //todo. За исключением стадии , на которой находят до несовпадений, на стадии для каждой строки требуется найти до несовпадений, а не до , как в алгоритме анализа текста.
|
pm[...][1...min{, }] = m+1 r = j = for i = to b = 0 if i < j merge(I, R, J, B) if b < min{} r = i extend(i, j, b)
|
Оценка работы
Теперь исследуем затраты времени на анализ текста. Если исключить вызовы процедур и , каждая из итераций цикла анализа текста выполняется за фиксированное время, что дает в общей сложности время . Общее число операций, выполняемых процедурой во время вызовов равно , так как она проверяет каждый символ текста не больше одного раза. Процедура при каждом вызове обрабатывает массив и , которые в сумме имеют элементов. Время работы можно рассчитать, соотнеся операции с фиксированным временем с каждым из этих входов, что дает время счета для каждого вызова, равное . Таким образом, можно видеть, что общее время анализа текста составляет .
Рассмотрим построение Используя аргументы, аналогичные применявшимся при проверке корректности процедуры merge, можно показать, что для нахождения требуемого количества несовпадений на стадии s требуется позиций, для которых выполняется условие B, и в особом случае, а именно, на стадии , требуется таких позиций.
На каждой стадии из стадий анализа образца цикл производит итераций . Если не считать время работы процедур и , каждая итерация требует фиксированного времени. Для всех итераций на шаге процедуре требуется время . Ранее было показано, что время работы пропорционально числу искомых несовпадений. Таким образом, каждый вызов занимает время , что равно . Таким образом, общее время для стадии равно = . Проведя суммирование по всем стадиям, получаем общее время счета = . Таким образом, общие затраты времени, включающие предварительную обработку образца и анализ текста, равны .
Пример
Пусть , , .
| tm | 1 | 2 | 3 | x[1..m] | y[i+1..i+m] |
| 0 | 2 | 3 | 4 | tram | thet |
| 1 | 1 | 2 | 3 | tram | hetr |
| 2 | 1 | 2 | 3 | tram | etri |
| 3 | 3 | 4 | 5 | tram | trip |
| 4 | 1 | 2 | 3 | tram | ripp |
| 5 | 1 | 2 | 3 | tram | ippe |
| 6 | 1 | 2 | 3 | tram | pped |
| 7 | 1 | 2 | 3 | tram | pedt |
| 8 | 1 | 2 | 3 | tram | edtr |
| 9 | 1 | 2 | 3 | tram | dtra |
| 10 | 4 | 5 | 5 | tram | trap |
| tm | 1 | 2 | 3 | 4 | 5 | x[1..m-i] | x[i+1..m] |
| 1 | 1 | 2 | 3 | 5 | 5 | tra | ram |
| 2 | 1 | 2 | 5 | 5 | 5 | tr | am |
| 3 | 1 | 5 | 5 | 5 | 5 | t | m |