<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=31.13.17.189&amp;*</id>
		<title>Викиконспекты - Вклад участника [ru]</title>
		<link rel="self" type="application/atom+xml" href="http://neerc.ifmo.ru/wiki/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=31.13.17.189&amp;*"/>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A1%D0%BB%D1%83%D0%B6%D0%B5%D0%B1%D0%BD%D0%B0%D1%8F:%D0%92%D0%BA%D0%BB%D0%B0%D0%B4/31.13.17.189"/>
		<updated>2026-06-11T14:16:45Z</updated>
		<subtitle>Вклад участника</subtitle>
		<generator>MediaWiki 1.30.0</generator>

	<entry>
		<id>http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%83%D1%80%D0%B1%D0%BE-%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%BE%D0%B9%D0%B5%D1%80%D0%B0-%D0%9C%D1%83%D1%80%D0%B0&amp;diff=66188</id>
		<title>Турбо-алгоритм Бойера-Мура</title>
		<link rel="alternate" type="text/html" href="http://neerc.ifmo.ru/wiki/index.php?title=%D0%A2%D1%83%D1%80%D0%B1%D0%BE-%D0%B0%D0%BB%D0%B3%D0%BE%D1%80%D0%B8%D1%82%D0%BC_%D0%91%D0%BE%D0%B9%D0%B5%D1%80%D0%B0-%D0%9C%D1%83%D1%80%D0%B0&amp;diff=66188"/>
				<updated>2018-08-07T14:55:28Z</updated>
		
		<summary type="html">&lt;p&gt;31.13.17.189: Отмена правки 65481, сделанной 185.220.101.4 (обсуждение)&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;'''Турбо-алгоритм Бойера-Мура''' (англ. ''Turbo Boyer-Moore'')  является улучшением [[Алгоритм Бойера-Мура|алгоритма Бойера-Мура]]. Турбо-алгоритм, разработанный группой учёных во главе с М.Крочемором, предлагает другой подход к коротким алфавитам и заодно решает вторую проблему — квадратичную сложность в худшем случае. Помимо эвристики стоп-символа и эвристики совпавшего суффикса, применяется третья эвристика — эвристика турбосдвига.&lt;br /&gt;
==Алгоритм==&lt;br /&gt;
Турбо-алгоритм Бойера-Мура не нуждается в дополнительном препроцессинге и требует только постоянную дополнительную память относительно оригинального алгоритма Бойера-Мура. Он состоит в запоминании сегмента текста, который соответствует суффиксу шаблона, совпавшему во время предыдущего шага алгоритма (и только тогда, когда сдвиг хорошего суффикса был выполнен).&lt;br /&gt;
Эта методика представляет два преимущества:&lt;br /&gt;
# Можно перепрыгнуть через этот сегмент.&lt;br /&gt;
# Она может позволить выполнение «турбо-сдвига».&lt;br /&gt;
Турбо-сдвиг может произойти, если мы обнаружим, что суффикс образца, который сходится с текстом, короче, чем тот, который был запомнен ранее.&lt;br /&gt;
&lt;br /&gt;
===Определение турбо-сдвига===&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;u&amp;lt;/tex&amp;gt; — запомненный сегмент, а &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; — cуффикс, совпавший во время текущей попытки, такой что &amp;lt;tex&amp;gt;uzv&amp;lt;/tex&amp;gt; — суффикс &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;av&amp;lt;/tex&amp;gt; — суффикс &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, два символа &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; встречаются на расстоянии &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt; в тексте, и суффикс &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt; длины &amp;lt;tex&amp;gt; \mathrm{size}(uzv)&amp;lt;/tex&amp;gt; имеет период длины &amp;lt;tex&amp;gt;p&amp;lt;/tex&amp;gt;, а значит не может перекрыть оба появления символов &amp;lt;tex&amp;gt;a&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;b&amp;lt;/tex&amp;gt; в тексте. Наименьший возможный сдвиг имеет длину &amp;lt;tex&amp;gt; \mathrm{size}(u) - \mathrm{size}(v)&amp;lt;/tex&amp;gt;  (его мы и называем турбо-сдвигом).[[Файл:Tbm1.png|600px|center]]&lt;br /&gt;
&lt;br /&gt;
Тем не менее, при &amp;lt;tex&amp;gt; \mathrm{size}(u) &amp;lt; \mathrm{size}(v)&amp;lt;/tex&amp;gt;, если длина сдвига плохого символа больше, чем длина сдвига хорошего суффикса и длины турбо-сдвига, то длина фактического сдвига должна быть больше или равна &amp;lt;tex&amp;gt; \mathrm{size}(u) + 1&amp;lt;/tex&amp;gt;. Действительно, в этом случае два символа &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; различны, так как мы предположили, что предыдущий сдвиг был сдвигом хороший суффикса. Тогда сдвиг больший, чем турбо-сдвиг, но меньший, чем &amp;lt;tex&amp;gt; \mathrm{size}(u) +1&amp;lt;/tex&amp;gt; будет выравнивать &amp;lt;tex&amp;gt;c&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;d&amp;lt;/tex&amp;gt; с таким же символом в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;, в этом случае длина фактического сдвига должна быть по крайней мере равен &amp;lt;tex&amp;gt; \mathrm{size}(u) +1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
[[Файл:Tbm2.png|600px|center]]&lt;br /&gt;
Нельзя совместить символы &amp;lt;tex&amp;gt;c \neq d&amp;lt;/tex&amp;gt; с одним и тем же символом в &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
===Описание алгоритма===&lt;br /&gt;
В [[Алгоритм Бойера-Мура|алгоритм Бойера-Мура]] дополнительно добавится запоминание длины &amp;lt;tex&amp;gt; \mathrm{size}(u)&amp;lt;/tex&amp;gt; сегмента текста, который соответствует суффиксу шаблона во время последней попытки, который мы не будем лишний раз рассматривать при сравнении суффиксов двух подстрок, а также запоминании размера сдвига &amp;lt;tex&amp;gt;\mathrm{shift}&amp;lt;/tex&amp;gt;, который мы совершили. Вычислять его будем следующим образом: &lt;br /&gt;
&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;\mathrm{size}(y) = n&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\mathrm{size}(x)=m&amp;lt;/tex&amp;gt; и &amp;lt;tex&amp;gt;\sigma&amp;lt;/tex&amp;gt; {{---}} размер алфавита.&lt;br /&gt;
&lt;br /&gt;
* Если текущем шаге у нас подстрока совпала с шаблоном &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;\mathrm{shift} = bmGs[0]&amp;lt;/tex&amp;gt; (&amp;lt;tex&amp;gt;bmGs[0]&amp;lt;/tex&amp;gt; равен периоду шаблона &amp;lt;tex&amp;gt;x&amp;lt;/tex&amp;gt;), &amp;lt;tex&amp;gt; \mathrm{size}(u) = m -  \mathrm{shift}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* Иначе возможны два случая:&lt;br /&gt;
** Если сдвиг хорошего суффикса не меньше турбо-сдвига и сдвига плохого символа, тогда &amp;lt;tex&amp;gt; \mathrm{shift} = bmGs[j+1]&amp;lt;/tex&amp;gt;,  &amp;lt;tex&amp;gt;\mathrm{size}(u) = \min(m - \mathrm{shift}, \mathrm{size}(v))&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;v&amp;lt;/tex&amp;gt; {{---}} текущая подстрока.&lt;br /&gt;
** В противном случае,  &amp;lt;tex&amp;gt; \mathrm{size}(u) = 0&amp;lt;/tex&amp;gt;, &amp;lt;tex&amp;gt;\mathrm{shift} = \max( \mathrm{turboShift}, \mathrm{bCShift})&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt; \mathrm{turboShift}&amp;lt;/tex&amp;gt; {{---}} длина турбо-сдвига, &amp;lt;tex&amp;gt; \mathrm{bCShift}&amp;lt;/tex&amp;gt; {{---}} длина сдвига плохого символа. Если турбо-сдвиг меньше сдвига плохого символа, то &amp;lt;tex&amp;gt; \mathrm{shift}&amp;lt;/tex&amp;gt; должен быть не больше &amp;lt;tex&amp;gt;\mathrm{size}(u_0) + 1&amp;lt;/tex&amp;gt;, где &amp;lt;tex&amp;gt;u_0&amp;lt;/tex&amp;gt; {{---}} сегмент текста, рассматриваемый на прошлом шаге.&lt;br /&gt;
&lt;br /&gt;
==Псевдокод==&lt;br /&gt;
Стадия препроцессинга совпадает со стадией препроцессинга в [[Алгоритм Бойера-Мура|алгоритме Бойера-Мура]], функция вычислений сдвигов плохих символов и функция вычисления хороших суффиксов не меняются, меняется только сам алгоритм, в него добавляется обработка турбо-сдвигов.&lt;br /&gt;
 &amp;lt;font color=green&amp;gt;//x {{---}} шаблон, y {{---}} текст, m {{---}} длина шаблона, n {{---}} длина текста&amp;lt;/font&amp;gt;&lt;br /&gt;
 '''function''' TBM(x: '''char'''[m], y: '''char'''[n]): '''List&amp;lt;int&amp;gt;'''   &lt;br /&gt;
    '''int''' i = 0&lt;br /&gt;
    '''int''' u = 0&lt;br /&gt;
    '''int''' shift = m&lt;br /&gt;
    &amp;lt;font color=green&amp;gt;//answer {{---}} массив, в который мы сохраняем индексы, начиная с которых, подстроки текста совпадают с шаблоном&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''List&amp;lt;int&amp;gt;''' answer&lt;br /&gt;
 &lt;br /&gt;
    '''if''' (m == 0)&lt;br /&gt;
         '''return'''&lt;br /&gt;
         &lt;br /&gt;
    &amp;lt;font color=green&amp;gt;//Предварительные вычисления&amp;lt;/font&amp;gt;&lt;br /&gt;
    '''int''' bmBc[] = preBmBc(x, m)&lt;br /&gt;
    '''int''' bmGs[] = preBmGs(x, m)&lt;br /&gt;
 &lt;br /&gt;
    '''while''' (i &amp;lt;= n - m) &lt;br /&gt;
        '''int''' j = m - 1&lt;br /&gt;
        '''while''' (j &amp;gt;= 0 '''and''' x[j] == y[i + j])&lt;br /&gt;
            --j&lt;br /&gt;
            '''if''' (u != 0 '''and''' j == m - 1 - shift) &lt;br /&gt;
                j -= u&lt;br /&gt;
        '''if''' (j &amp;lt; 0) &lt;br /&gt;
            answer.add(i)&lt;br /&gt;
            shift = bmGs[0]&lt;br /&gt;
            u = m - shift&lt;br /&gt;
        '''else''' &lt;br /&gt;
            '''int''' v = m - 1 - j&lt;br /&gt;
            '''int''' turboShift = u - v&lt;br /&gt;
            '''int''' bCShift = bmBc[y[i + j]] - m + j + 1&lt;br /&gt;
            shift = max(turboShift, bCShift, bmGs[j + 1])&lt;br /&gt;
            '''if''' (shift == bmGs[j + 1])&lt;br /&gt;
                u = min((m - shift), v)&lt;br /&gt;
            '''else''' &lt;br /&gt;
                '''if''' (turboShift &amp;lt; bcShift) &lt;br /&gt;
                    shift = min(shift, (u + 1))&lt;br /&gt;
                u = 0&lt;br /&gt;
        i += shift&lt;br /&gt;
    '''return''' answer&lt;br /&gt;
&lt;br /&gt;
==Асимптотика==&lt;br /&gt;
{{Утверждение|statement= Фаза препроцессинга требует &amp;lt;tex&amp;gt;O(m + \sigma)&amp;lt;/tex&amp;gt; времени и памяти, где &amp;lt;tex&amp;gt;\sigma&amp;lt;/tex&amp;gt; {{---}} размер алфавита. &lt;br /&gt;
|proof= Стадия препроцессинга совпадает со стадией препроцессинга в [[Алгоритм Бойера-Мура|алгоритме Бойера-Мура]]&amp;lt;ref&amp;gt;В этом конспекте приведена реализация за &amp;lt;tex&amp;gt;O(n^2)&amp;lt;/tex&amp;gt; и неконстантную память, реализацию за &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; и константную память можно посмотреть вот [http://www-igm.univ-mlv.fr/~lecroq/string/node14.html#SECTION00140 тут] &amp;lt;/ref&amp;gt;, поэтому рассмотрим только стадию поиска.}}&lt;br /&gt;
{{Утверждение|statement= Фаза поиска требует &amp;lt;tex&amp;gt;O(n)&amp;lt;/tex&amp;gt; времени, где &amp;lt;tex&amp;gt;n&amp;lt;/tex&amp;gt; {{---}} длина строки, в которой выполняется поиск.&lt;br /&gt;
}}&lt;br /&gt;
{{Утверждение|statement= В худшем случае поиск требует &amp;lt;tex&amp;gt;O(2n)&amp;lt;/tex&amp;gt; сравнений.&lt;br /&gt;
|proof= Так как мы запоминаем последний просмотренный сегмент текста, совпадающий с суффиксом шаблона, это позволяет нам пропускать его при нахождении очередного (нам незачем второй раз просматривать сегмент, про который известно, что он совпадает), что уменьшет число сравнений и хождений по строке. Докажем, что число сравнений после такой оптимизаций будет &amp;lt;tex&amp;gt;O(2n)&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Разобьём поиск на шаги, каждый из которых будет состоять из двух операций: сканирования и сдвига. На шаге &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; мы будем называть &amp;lt;tex&amp;gt;suf_k&amp;lt;/tex&amp;gt; длину суффикса шаблона, что совпадает с текстом, перед суффиксом шаблона будет символ, который не совпадает с соответствующим символом в тексте (в случае когда &amp;lt;tex&amp;gt;suf_k&amp;lt;/tex&amp;gt; не соответствует длине шаблона). Мы также будем называть &amp;lt;tex&amp;gt;shift_k&amp;lt;/tex&amp;gt; длину сдвига, сделанного на шаге &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим три типа шагов в зависимости от характера сканирования и сдвига. Мы говорим, что сдвиг на шаге &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; короткий, если &amp;lt;tex&amp;gt;2shift_k &amp;lt; suf_k + 1&amp;lt;/tex&amp;gt;. Тогда эти три типа будут: &lt;br /&gt;
# Шаг с последующим шагом с прыжком.&lt;br /&gt;
# Шаг с длинным сдвигом, без последующего шага с прыжком.&lt;br /&gt;
# Шаг с коротким сдвигом, без последующего шага с прыжком.&lt;br /&gt;
Идея доказательства состоит в [[Амортизационный_анализ|амортизации]] стоимости сравнения со сдвигами. Определим стоимость шага &amp;lt;tex&amp;gt;cost_k&amp;lt;/tex&amp;gt; следующим образом:&lt;br /&gt;
* Если шаг &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; имеет тип (1), &amp;lt;tex&amp;gt;cost_k = 1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
* Если шаг &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; имеет тип (2) или (3), стоимость &amp;lt;tex&amp;gt;cost_k = suf_k + 1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Общее количество сравнений, выполняемых алгоритмом {{---}} сумма стоимостей шагов. Мы хотим доказать, что &amp;lt;tex&amp;gt; \sum cost &amp;lt; 2 \sum shifts&amp;lt;/tex&amp;gt;. Во второй &amp;lt;tex&amp;gt; \sum &amp;lt;/tex&amp;gt; длину последнего сдвига заменим &amp;lt;tex&amp;gt;m&amp;lt;/tex&amp;gt;.&lt;br /&gt;
В случае шага типа (1), стоимость соответствует единственному сравнению несовпадающих символов. Другие сравнения, проведенные в течение того же шага, являются&lt;br /&gt;
стоимостью последующих шагов.&lt;br /&gt;
&lt;br /&gt;
Рассмотрим каждый тип шага:&lt;br /&gt;
# &amp;lt;tex&amp;gt;cost_k = 1&amp;lt;/tex&amp;gt; очевидным образом меньше, чем &amp;lt;tex&amp;gt;2shift_k&amp;lt;/tex&amp;gt;, так как &amp;lt;tex&amp;gt;shift_k &amp;gt; 0&amp;lt;/tex&amp;gt;.&lt;br /&gt;
# &amp;lt;tex&amp;gt;cost_k = suf_k + 1 \leqslant 2 shift_k&amp;lt;/tex&amp;gt;, по определению длинных сдвигов.&lt;br /&gt;
# Так как в этой ситуации мы имеем &amp;lt;tex&amp;gt;shift_k &amp;lt; suf_k&amp;lt;/tex&amp;gt;, единственный возможный вариант, это когда обычный сдвиг применяется на шаге &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;. Тогда мы должны это запомнить. На следующем шаге, &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt;, мы что-то запомнили, что приводит к возможному турбо-сдвигу. Ситуация на шаге &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; {{---}} основная ситуация, когда турбо-сдвиг возможен. Прежде чем продолжить доказательство, мы сначала рассмотрим два случая и установим неравенства (по стоимости шага &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt;), которые используем позже.&lt;br /&gt;
#* Случай (а): &amp;lt;tex&amp;gt;suf_k + shift_k \leqslant |p|&amp;lt;/tex&amp;gt;. По определению турбо-сдвига, мы имеем &amp;lt;tex&amp;gt;suf_k - suf_{k+1} &amp;lt; shift_{k + 1}&amp;lt;/tex&amp;gt;. Таким образом, &amp;lt;tex&amp;gt;cost_k = sufk + 1 \leqslant suf_{k+1} + shift_{k+1} + 1 \leqslant shift_k + shift_{k + 1}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
#* Случай (б): &amp;lt;tex&amp;gt;suf_k + shift_k &amp;gt; |p|&amp;lt;/tex&amp;gt;. По определению турбо-сдвига, мы имеем &amp;lt;tex&amp;gt;suf_{k+1} + shift_k + shift_{k + 1} \geqslant m&amp;lt;/tex&amp;gt;. Тогда &amp;lt;tex&amp;gt;cost_k \leqslant m \leqslant 2shift_k - 1 + shift_{k + 1}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
: Можно считать, что на шаге &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; случай (б) имеет место, потому что это дает нам верхнюю границу &amp;lt;tex&amp;gt;cost_k&amp;lt;/tex&amp;gt; (это верно, если &amp;lt;tex&amp;gt;shift_k \geqslant 2&amp;lt;/tex&amp;gt;, случай &amp;lt;tex&amp;gt;shift_k = 1&amp;lt;/tex&amp;gt; можно обрабатывать напрямую). Если шаг &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; типа (1), то &amp;lt;tex&amp;gt;cost_{k + 1} = 1&amp;lt;/tex&amp;gt;, а затем &amp;lt;tex&amp;gt;cost_k + cost_{k+1} \leqslant 2shift_k + shift_{k+1}&amp;lt;/tex&amp;gt;, что даже лучше, чем ожидалось. Если на шаге &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; мы имеем &amp;lt;tex&amp;gt;suf_{k + 1} \leqslant shift_{k + 1}&amp;lt;/tex&amp;gt;, то мы получим то, что ожидалось: &amp;lt;tex&amp;gt;cost_k + cost_{k + 1} \leqslant 2shift_k + 2shift_{k + 1}&amp;lt;/tex&amp;gt;. Последняя ситуация для рассмотрения, когда на шаге &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt; мы имеем &amp;lt;tex&amp;gt;suf_{k + 1} &amp;gt; shift_{k + 1}&amp;lt;/tex&amp;gt;. Это означает, что, как уже упоминалось ранее, обычный сдвиг применяется на шаге &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt;. Таким образом, приведенный выше анализ также применяется на шаге &amp;lt;tex&amp;gt;k + 1&amp;lt;/tex&amp;gt;, и, так как только случай (а) может произойти, мы получаем &amp;lt;tex&amp;gt;cost_{k + 1} \leqslant shift_{k + 1} + shift_{k + 2}&amp;lt;/tex&amp;gt;. Мы, наконец, получаем &amp;lt;tex&amp;gt;cost_k + cost_{k + 1} \leqslant 2shift_k + 2shift_{k + 1} + shift_{k + 2}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Покажем правильность шагов по индукции: если все шаги &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; до &amp;lt;tex&amp;gt;k + j&amp;lt;/tex&amp;gt; таковы, что &amp;lt;tex&amp;gt;suf_k &amp;gt; shift_k,... , suf_{k + j} &amp;gt; shift_{k + j}&amp;lt;/tex&amp;gt;, то &amp;lt;tex&amp;gt;cost_k + ... + cost_{k + j} \leqslant 2shift_k + ... + 2shift_{k + j} + shift_{k + j + 1}&amp;lt;/tex&amp;gt;. &amp;lt;br /&amp;gt;&lt;br /&gt;
Пусть &amp;lt;tex&amp;gt;k'&amp;lt;/tex&amp;gt; первый этап после этапа &amp;lt;tex&amp;gt;k&amp;lt;/tex&amp;gt; такой, что &amp;lt;tex&amp;gt;suf_{k'} \leqslant shift_{k'}&amp;lt;/tex&amp;gt;. Целое число &amp;lt;tex&amp;gt;k'&amp;lt;/tex&amp;gt; существует потому, что иначе получим бесконечную последовательность сдвигов с уменьшающейся длиной. После этого мы получим &amp;lt;tex&amp;gt;cost_k + ... + cost_{k'} \leqslant 2shift_k + ... + 2shift_{k'}&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Это показывает нам, что &amp;lt;tex&amp;gt; \sum cost_k \leqslant 2 \sum shift_k&amp;lt;/tex&amp;gt;, что и требовалось.}}&lt;br /&gt;
&lt;br /&gt;
==Пример работы==&lt;br /&gt;
Пусть нам дана строка &amp;lt;tex&amp;gt;y = GCATCGCAGAGAGTATACAGTACG&amp;lt;/tex&amp;gt; и образец &amp;lt;tex&amp;gt;x=GCAGAGAG&amp;lt;/tex&amp;gt;.&lt;br /&gt;
&lt;br /&gt;
Построим массив &amp;lt;tex&amp;gt;bmBc&amp;lt;/tex&amp;gt;:&lt;br /&gt;
&lt;br /&gt;
[[Файл:RaitaPre.png|250px]]&lt;br /&gt;
&lt;br /&gt;
Рассмотрим шаги алгоритма:&lt;br /&gt;
&lt;br /&gt;
{| class = &amp;quot;wikitable&amp;quot;&lt;br /&gt;
! Изображение !! &amp;lt;tex&amp;gt;(j, bmBc[y[j]])&amp;lt;/tex&amp;gt; !! Описание&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
|[[Файл:Raita1.png|550px]]&lt;br /&gt;
|&amp;lt;tex&amp;gt;(7, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|Сравниваем последние символы, они неравны, поэтому сдвигаемся на &amp;lt;tex&amp;gt;bmGs[7] = bmBc[A]-8+8 = 1&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
|[[Файл:Tbme2.PNG|550px]]&lt;br /&gt;
|&amp;lt;tex&amp;gt;(8, 2)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|Последние два символа совпали, сдвигаемся на &amp;lt;tex&amp;gt;bmGs[5] = bmBc[C] - 8 + 6 = 4&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
|[[Файл:Tbme3.PNG|550px]]&lt;br /&gt;
|&amp;lt;tex&amp;gt;(12, 2)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|Все символы совпали, Продолжим работу (для примера, в обычном варианте на этом этапе мы можем выйти, если требуется найти только одно вхождение) и сдвинемся на &amp;lt;tex&amp;gt;bmGs[0] = 7&amp;lt;/tex&amp;gt;. &lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
|[[Файл:Tbme4.PNG|550px]]&lt;br /&gt;
|&amp;lt;tex&amp;gt;(19, 2)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|Последние два символа совпали, сдвигаемся на &amp;lt;tex&amp;gt;bmGs[5] = bmBc[C] - 8 + 6 = 4&amp;lt;/tex&amp;gt;.&lt;br /&gt;
|-align=&amp;quot;center&amp;quot;&lt;br /&gt;
|[[Файл:Tbme5.PNG|550px]]&lt;br /&gt;
|&amp;lt;tex&amp;gt;(23, 1)&amp;lt;/tex&amp;gt;&lt;br /&gt;
|Последние символы совпали, сравниваем предпоследние, сдвигаемся. Строка закончилась, выходим. &lt;br /&gt;
|-&lt;br /&gt;
|}&lt;br /&gt;
&lt;br /&gt;
В итоге, чтобы найти одно вхождение образца длиной &amp;lt;tex&amp;gt;m = 8&amp;lt;/tex&amp;gt; в образце длиной &amp;lt;tex&amp;gt;n = 24&amp;lt;/tex&amp;gt; нам понадобилось &amp;lt;tex&amp;gt;15&amp;lt;/tex&amp;gt; сравнений символов.&lt;br /&gt;
&lt;br /&gt;
==См. также==&lt;br /&gt;
* [[Алгоритм Бойера-Мура]]&lt;br /&gt;
* [[Алгоритм Райта]]&lt;br /&gt;
* [[Алгоритм Кнута-Морриса-Пратта|Алгоритм Кнута-Морриса-Пратта]]&lt;br /&gt;
* [[Алгоритм Апостолико-Крочемора|Алгоритм Апостолико-Крочемора]]&lt;br /&gt;
&lt;br /&gt;
==Примечания==&lt;br /&gt;
&lt;br /&gt;
&amp;lt;references /&amp;gt;&lt;br /&gt;
&lt;br /&gt;
==Источники информации==&lt;br /&gt;
* [[wikipedia:ru:Алгоритм_Бойера_—_Мура|Википедия {{---}} Алгоритм Бойера-Мура]]&lt;br /&gt;
* [[wikipedia:Boyer–Moore_string_search_algorithm|Wikipedia {{---}} Boyer–Moore string search algorithm]]&lt;br /&gt;
* [http://www-igm.univ-mlv.fr/~lecroq/string/node15.html#SECTION00150 Turbo Boyer-Moore algorithm]&lt;br /&gt;
* [http://algolist.manual.ru/search/esearch/turbo_bm.php Турбо Боуер-Мур]&lt;br /&gt;
* [http://igm.univ-mlv.fr/~mac/Articles-PDF/CCGJLPR94algo-speedup.pdf Speeding Up Two String-Matching Algorithms]&lt;br /&gt;
&lt;br /&gt;
[[Категория:Алгоритмы и структуры данных]]&lt;br /&gt;
[[Категория:Поиск подстроки в строке]]&lt;br /&gt;
[[Категория:Точный поиск]]&lt;/div&gt;</summary>
		<author><name>31.13.17.189</name></author>	</entry>

	</feed>