|
Поиск подстрок
Поиск подстрок: базовые понятия и наивный алгоритм
Match1°. Дана строка S и целые числа i, j, не превосходящие длины строки S. Позиции в строке нумеруются от 1. Через S[i..j] обозначается подстрока S, начинающаяся в позиции i и оканчивающаяся в позиции j. Если i > j, то S[i..j] считается пустой строкой (длина пустой строки равна 0). Вывести длину подстроки S[i..j] и все ее символы (в порядке слева направо).
Match2°. Дана строка S и числа i, j, не превосходящие длины строки S. Префиксом строки S называется любая ее подстрока вида S[1..k], k ≤ |S| (|S| обозначает длину строки S). Если префикс строки S является непустым и не совпадает со всей строкой, то он называется собственным префиксом. Вывести количество префиксов подстроки S[i..j], а также длину и символы каждого ее префикса, перебирая префиксы в порядке возрастания их длин, а символы каждого префикса — в порядке слева направо.
Match3°. Дана строка S и числа i, j, не превосходящие длины строки S. Суффиксом строки S называется любая ее подстрока вида S[k..|S|], k ≥ 1 (|S| обозначает длину строки S). Если суффикс строки S является непустым и не совпадает со всей строкой, то он называется собственным суффиксом. Вывести количество суффиксов подстроки S[i..j], а также длину и символы каждого ее суффикса, перебирая суффиксы в порядке убывания их длин, а символы каждого суффикса — в порядке слева направо.
Match4°. Даны строки P, T и число k. Строка P считается образцом (англ. pattern), строка T — текстом, в котором ищется образец. Известно, что длина суффикса строки T, начинающегося в позиции k, больше или равна |P|. Используя посимвольное сравнение, выполняемое слева направо, проверить, входит ли образец P в текст T, начиная с позиции k. Если входит, то вывести True, иначе вывести False. Вывести также количество потребовавшихся сравнений символов.
Match5°. Даны строки P и T. Найти первое вхождение строки P в текст T, используя наивный алгоритм поиска, при котором выполняется посимвольное сравнение P с каждой из подстрок T длины |P|. Подстроки T перебираются слева направо, символы строк также сравниваются слева направо. При каждом сравнении символов (независимо от успешности сравнения) выводить сравниваемый символ строки P. После завершения алгоритма вывести позицию в T, с которой начинается первое вхождение P, или 0, если вхождения отсутствуют.
Match6°. Даны строки P и T. Найти первое вхождение строки P в текст T, используя модификацию наивного алгоритм поиска (см. Match5), при которой подстроки T перебираются слева направо, а посимвольное сравнение строк выполняется справа налево. При каждом сравнении символов (независимо от успешности сравнения) выводить сравниваемый символ строки P. После завершения алгоритма вывести позицию в T, с которой начинается первое вхождение P, или 0, если вхождения отсутствуют.
Match7°. Даны строки P и T. Найти все вхождения строки P в текст T, используя наивный алгоритм поиска (см. Match5). Вывести позиции в T, с которых начинаются вхождения образца P. Вывести также общее количество сравнений символов, которое потребовалось для решения задачи.
Match8°. Даны строки P и T. Найти все вхождения строки P в текст T, используя модификацию наивного алгоритма поиска (см. Match6). Вывести позиции в T, с которых начинаются вхождения образца P. Вывести также общее количество сравнений символов, которое потребовалось для решения задачи.
Основной препроцессинг: базовые понятия и быстрый алгоритм
Match9°. Дана строка S и число i (2 ≤ i ≤ |S|). Через Zi(S) обозначается длина наибольшей подстроки S, которая начинается в позиции i и совпадает с префиксом строки S. Если требуемые подстроки отсутствуют, то Zi(S) = 0. Используя посимвольное сравнение строк, найти Zi(S). Вывести найденное значение, а также количество сравнений символов, потребовавшееся для его нахождения.
Match10°. Дана строка S. Z-блоком строки S в позиции i (> 1) называется непустая строка S[i..i + Zi(S) − 1], т. е. подстрока S, начинающаяся в позиции i > 1 и имеющая ненулевую длину Zi(S) (определение Zi(S) см. в Match9). Известно, что в данной строке S имеется хотя бы один Z-блок длины, большей 2. Используя посимвольное сравнение строк и перебирая позиции в порядке возрастания, найти первый из Z-блоков с указанным свойством. Вывести позицию i найденного Z-блока, его длину Zi(S), а также количество сравнений символов, потребовавшееся для решения задачи.
Match11°. Дана строка S. Используя посимвольное сравнение строк и перебирая позиции в порядке возрастания, найти все Z-блоки строки S (определение Z-блока см. в Match10). Для каждого найденного Z-блока вывести его позицию и длину. Кроме того, вывести количество сравнений символов, потребовавшееся для решения задачи.
Match12°. Дана строка S и число k (2 ≤ k ≤ |S|). Через ri(S) обозначается крайний правый конец Z-блоков строки S (см. Match10), начинающихся не позднее позиции i строки S, или 0, если требуемые Z-блоки отсутствуют. Таким образом, ненулевое значение ri(S) можно найти по формуле ri(S) = max{j + Zj(S) − 1}, где j меняется от 2 до i, причем Zj(S) > 0. При этом через li(S) обозначается то значение j, на котором достигается указанный выше максимум (если таких значений j несколько, то через li(S) обозначается наибольшее из них). Для ri(S) = 0 значение li(S) полагается равным 0. Используя посимвольное сравнение строк для вычисления Zi(S), найти и вывести ri(S) и li(S), i = 2, …, k. Вывести также общее количество сравнений символов, потребовавшееся для решения задачи.
Match13°. Дана строка S. Описать числовой массив Z для хранения значений Zi(S) (см. Match9) и числовые переменные R и L. Реализовать первый шаг быстрого алгоритма основного препроцессинга: используя посимвольное сравнение, найти Z2 и положить начальные значения для переменных R и L равными соответственно r2(S) и l2(S) (см. Match12). Оформить алгоритм в виде вспомогательной подпрограммы. Вывести Z2, R, L и количество сравнений символов, потребовавшееся для их нахождения.
Match14°. Дана строка S, число k (2 < k ≤ |S|) и значения R = rk−1 и L = lk−1. Известно, что k > R. Реализовать для данной ситуации k-й шаг быстрого алгоритма основного препроцессинга. Для этого найти Zk, используя посимвольное сравнение, и положить значения R и L равными соответственно rk и lk (R = k + Zk − 1, L = k, если Zk > 0; в противном случае R и L не изменяются). Оформить алгоритм в виде вспомогательной подпрограммы. Вывести Zk, R, L и количество сравнений символов, потребовавшееся для их нахождения.
Match15°. Дана строка S, число k (2 < k ≤ |S|), значения R = rk−1 и L = lk−1, а также значения Zi, i = 2, …, k − 1. Известно, что k ≤ R. Реализовать для данной ситуации k-й шаг быстрого алгоритма основного препроцессинга. При этом учесть, что в силу неравенства k ≤ R подстрока S' = S[k..R] входит в Z-блок S[L..R], который (по определению Z-блока) совпадает с префиксом S[1..ZL]. Поэтому S' = S[k'..ZL], где k' = k − L + 1, и, следовательно, подстрока, начинающаяся с позиции k, должна совпадать, по меньшей мере, с префиксом S длины min{Zk', |S'|} (|S'| = R − k + 1). Если при этом Zk' < |S'|, то следует положить Zk = Zk'; R и L при этом не изменяются. Если же Zk' ≥ |S'|, то надо выполнить дополнительную проверку, сравнивая до несовпадения символы S[p], начиная с p = |S'| + 1, и S[q], начиная с q = R + 1; если q достигнет значения |S| + 1 или в позиции q ≥ R + 1 обнаружится несовпадение, то следует положить Zk = q − k, R = q − 1, L = k. В любом случае R и L окажутся равными rk и lk соответственно. Оформить алгоритм в виде вспомогательной подпрограммы. Вывести Zk, R, L и количество сравнений символов, потребовавшееся для их нахождения (при Zk' < |S'| данное количество будет равно 0).
Match16°. Дана строка S. Найти Zi(S), i = 2, …, |S|, используя быстрый алгоритм препроцессинга, описанный в Match13–Match15. Вывести найденные Zi(S), а также количество сравнений символов, потребовавшееся при выполнении алгоритма.
Поиск с использованием основного препроцессинга
Match17°. Даны строки P и T, не содержащие символ «$». Реализовать быстрый алгоритм поиска всех вхождений P в T, сформировав строку S = P + «$» + T и выполнив для нее основной препроцессинг (см. Match16). Каждому вхождению P в T соответствует значение Zi(S), равное |P| (очевидно, i > |P| + 1); при этом данное вхождение начинается в позиции i − |P| − 1 строки T. Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также количество сравнений символов, потребовавшееся при выполнении алгоритма.
Match18°. Даны строки P и T, не содержащие символ «$». Найти все вхождения P в T, рассматривая строку T как циклическую (после последнего символа строки T опять берется ее первый символ). Для этого сформировать строку S = P + «$» + T + T', где T' = T[1..|P| − 1], и использовать для нее быстрый алгоритм основного препроцессинга (см. Match16). Вывести начальные позиции всех найденных вхождений (в порядке возрастания), а также количество сравнений символов, потребовавшееся при выполнении алгоритма.
Match19°. Даны строки A и B, не содержащие символ «$». Найти наибольший суффикс строки A, который одновременно является префиксом строки B, и вывести его длину (или 0, если требуемый суффикс отсутствует). Для этого сформировать строку S = B + «$» + A и с помощью быстрого алгоритма основного препроцессинга (см. Match16) найти q = max Zi(S), где i пробегает все значения, для которых ri(S) = |A| + |B| + 1. Вывести также количество сравнений символов, потребовавшееся при выполнении алгоритма.
Match20°. Даны строки A и B одинаковой длины, не содержащие символ «$». Определить, является ли строка B циклическим сдвигом строки A, и при положительном ответе вывести минимальную величину соответствующего левого сдвига (при отрицательном ответе вывести −1). Например, для строк A = «abcd» и B = «bcda» надо вывести значение 1, а для строк A = «aaa» и B = «aaa» — значение 0. Для этого сформировать строку S = A + «$» + B и с помощью быстрого алгоритма основного препроцессинга (см. Match16) найти q = max Zi(S), где i пробегает все значения, для которых ri(S) = 2|A| + 1. Если q = 0, то вывести −1, иначе выполнить посимвольное сравнение оставшейся части строк A и B, и, в зависимости от результатов этого сравнения, вывести −1 или величину левого сдвига (эта величина будет определяться через q). Вывести также количество сравнений символов, потребовавшееся при решении задачи.
Метод Кнута–Морриса–Пратта
Match21°. Дана строка P и число i (≤ |P|). Через spi(P) обозначается длина наибольшего собственного суффикса подстроки P[1..i], который совпадает с префиксом P (обозначение образовано начальными буквами слов «suffix» и «prefix»). Если требуемые суффиксы отсутствуют, то spi(P) = 0. Вывести spi(P).
Match22°. Дана строка P и число k (≤ |P|). Через sp'i(P), i = 1, …, |P| − 1, обозначается длина наибольшего собственного суффикса подстроки P[1..i], который совпадает с префиксом P и для которого выполняется дополнительное условие: символы в позициях i + 1 и sp'i(P) + 1 не равны. Таким образом, sp'i(P) ≤ spi(P) (величина spi(P) определена в Match21). В случае i = |P| по определению полагается sp'|P|(P) = sp|P|(P). Вывести sp'i(P) для i = k, …, |P|.
Match23°. Дана строка P и число i (≤ |P| + 1). Через FP(i) и F'P(i) обозначаются соответственно слабая и сильная функции неудачи для строки P: FP(i) = spi−1(P) + 1, F'P(i) = sp'i−1(P) + 1 (значения spi(P) определены в Match21, а значения sp'i(P) — в Match22). При этом дополнительно предполагается, что sp0(P) = sp'0(P) = 0. Найти FP(i) и F'P(i).
Match24°. Даны строки P, T и значения слабой функции неудач для строки P: FP(i), i = 1, …, |P| + 1 (см. Match23). Найти все вхождения P в T, используя метод Кнута–Морриса–Пратта (метод КМП). Для этого использовать переменные p и t, хранящие текущие позиции строк P и T соответственно, инициализировав их значениями 1. Пока истинно условие |P| − p ≤ |T| − t, выполнять следующие действия: • пока p ≤ |P| и P[p] = T[t], увеличивать на 1 переменные p и t; • равенство p = |P| + 1 означает, что обнаружено очередное вхождение P в T (начиная с позиции t − |P|); • если p = 1, то увеличить t на 1; • положить переменную p равной значению слабой функции неудач FP(p). Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также количество сравнений символов, потребовавшееся при выполнении алгоритма. Примечание. Ускорение в методе КМП (по сравнению с наивным алгоритмом поиска) достигается за счет того, что изменение значения p (интерпретируемое как сдвиг образца P вправо относительно текста T) может выполняться на величину, большую 1. А именно, если несовпадение символов обнаружилось для P[i + 1] и T[t], то строка P сразу сдвигается вправо на i − spi(P) позиций (так что совмещаются символы P[spi(P) + 1] и T[t]). При этом гарантируется, что spi(P) начальных позиций в P совпадут с соответствующими позициями строки T, поэтому очередная проверка выполняется для символов P[spi(P) + 1] и T[t].
Match25°. Даны строки P, T и значения сильной функции неудач для строки P: F'P(i), i = 1, …, |P| + 1 (см. Match23). Найти все вхождения P в T, используя модифицированный метод Кнута–Морриса–Пратта, отличающийся от исходного метода КМП (см. Match24) тем, что вместо функции FP в нем используется сильная функция неудач F'P. Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также количество сравнений символов, потребовавшееся при выполнении алгоритма. Примечание. Ускорение модифицированного метода КМП по сравнению с исходным состоит в том, что при сдвиге строки P вправо на i + sp'i(P) позиций новый символ строки P, совмещенный с текущей позицией t строки T, будет заведомо отличаться от прежнего символа, для которого уже выявлено несовпадение.
Препроцессинг для метода Кнута–Морриса–Пратта
Match26°. Дано число n и набор значений Zi(P), i = 2, …, n, для некоторой строки P длины n (см. Match9). Найти значения sp'i(P) (см. Match22), используя соотношение sp'i(P) = Zj(P), где j > 1 — наименьший индекс, такой что i = j + Zj(P) − 1 (данное соотношение справедливо для любого i > 1), а также соотношение sp'1(P) = 0. Перебор j организовать в цикле с шагом −1 от n до 2, условные операторы не использовать. Вывести найденные значения sp'i(P) для i = 1, …, n.
Match27°. Дано число n и набор значений Zi(P), i = 2, …, n, для некоторой строки P длины n. Найти значения spi(P) (см. Match21), используя формулы для sp'i(P), приведенные в Match26, а также соотношения sp1(P) = 0, spn(P) = sp'n(P), spi(P) = max{spi+1(P) − 1, sp'i(P)}, i = 2, …, n − 1. Вывести найденные значения spi(P) для i = 1, …, n.
Match28°. Даны строки P и T. Используя модифицированный метод КМП (см. Match25), найти все вхождения P в T. Для вычисления сильной функции неудач F'P использовать быстрый алгоритм основного препроцессинга (см. Match16) и формулы для sp'i, приведенные в Match26. Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также найденные в ходе основного препроцессинга значения Zi(P), i = 2, …, |P|, и количество сравнений символов, потребовавшееся при выполнении алгоритма (в том числе и при проведении основного препроцессинга).
Match29°. Даны строки P и T. Используя метод КМП (см. Match24), найти все вхождения P в T. Для вычисления слабой функции неудач FP использовать быстрый алгоритм основного препроцессинга (см. Match16) и формулы для spi, приведенные в Match27. Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также найденные в ходе основного препроцессинга значения Zi(P), i = 2, …, |P|, и количество сравнений символов, потребовавшееся при выполнении алгоритма (в том числе и при проведении основного препроцессинга).
Match30°. Дана строка P, число k (< |P|) и значения spi(P), i = 1, …, k. Найти значение spk+1(P), используя следующий алгоритм (препроцессинг по методу КМП). Положить x = P[k + 1] и v = spk(P). Пока символ P[v + 1] не совпадает с x и v > 0, выполнять переприсваивание v = spv(P) («рекурсивный спуск»). Если после завершения рекурсивного спуска символ P[v + 1] равен x, то значение spk+1(P) положить равным v + 1, в противном случае spk+1(P) = 0. Вывести значение spk+1(P) и количество сравнений символов, потребовавшееся при выполнении алгоритма. Примечание. В алгоритме фактически требуется найти P' — наибольший собственный префикс подстроки P[1..k], который совпадает с суффиксом P[1..k] и за которым (в позиции |P'|+1) следует символ x. Первый шаг алгоритма почти очевиден: если x совпадает с символом P[spk(P) + 1], то spk+1(P) ≥ spk(P) + 1, и достаточно доказать, что оценка spk+1(P) > spk(P) + 1 никогда не выполняется (доказывается от противного). Отсутствие совпадения равносильно оценке spk+1(P) ≤ spk(P). Используя эту оценку, можно доказать, что искомая строка P' представляет собой наибольший собственный префикс P'' подстроки P[1..spk(P)], который совпадает с суффиксом P[1..k] и за которым (в позиции |P''| + 1) следует символ x. Сравнивая данное утверждение с первым предложением настоящего примечания, получаем алгоритм рекурсивного спуска.
Match31°. Дана строка P и число k (≤ |P|). Найти значения spi(P), i = 1, …, k, используя алгоритм препроцессинга по методу КМП, описанный в Match30 (в качестве начального шага алгоритма положить sp1(P) = 0). Вывести полученные значения, а также количество сравнений символов, потребовавшееся для их нахождения.
Match32°. Дана строка P. Найти значения sp'i(P), i = 1, …, |P| (см. Match22). Для этого предварительно определить значения spi(P), используя алгоритм препроцессинга по методу КМП (см. Match31). Для нахождения sp'i(P) использовать следующий рекурсивный алгоритм (значения i перебираются от 1 до |P|): если spi(P) = 0, или i = |P|, или символы в позициях i + 1 и spi(P) + 1 не равны, то sp'i(P) = spi(P), в противном случае sp'i(P) = sp'v(P), где v = spi(P). Вывести полученные значения sp'i(P) и количество сравнений символов, потребовавшееся для их нахождения.
Match33°. Даны строки P и T. Используя метод КМП (см. Match24), найти все вхождения P в T. Для вычисления слабой функции неудач FP использовать алгоритм препроцессинга по методу КМП (см. Match31). Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также значения слабой функции неудач FP(i), i = 1, …, |P| + 1, и количество сравнений символов, потребовавшееся при выполнении алгоритма (в том числе и при проведении препроцессинга).
Match34°. Даны строки P и T. Используя модифицированный метод КМП (см. Match25), найти все вхождения P в T. Для вычисления сильной функции неудач F'P использовать алгоритм, приведенный в Match32. Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также значения сильной функции неудач F'P(i), i = 1, …, |P| + 1, и количество сравнений символов, потребовавшееся при выполнении алгоритма (в том числе и при проведении препроцессинга).
Метод реального времени
Match35°. Дана строка P и число k (≤ |P|). Через spi,x(P) (1 ≤ i ≤ |P|, x — некоторый символ) обозначается длина наибольшего собственного суффикса подстроки P[1..i], который совпадает с префиксом P и для которого выполняется дополнительное условие: символ в позиции spi,x(P) + 1 равен x. Если требуемые суффиксы отсутствуют, то spi,x(P) полагается равным 0 при P[1] = x и −1 в противном случае. Найти и вывести spi,x(P) для i = 1, …, |P|, используя в качестве x символ P[k].
Match36°. Даны строки P, T и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Кроме того, для каждой буквы x из Σ в алфавитном порядке («a», «b», «c», …) даны значения spi,x(P), i = 1, …, |P| (см. Match35). Найти все вхождения P в T, используя метод реального времени, имеющий следующие отличия от метода КМП (см. Match24): • дополнительное действие при p = 1 не выполняется; • значение p заменяется не на FP(p) (равное spp−1(P) + 1), а на spp−1,x(P) + 2, где в качестве x указывается символ T[t], причем это действие выполняется только при наличии двух условий: p > 1 и t ≤ |T|; • в конце каждой итерации внешнего цикла значение t увеличивается на 1. Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также количество сравнений символов, потребовавшееся при выполнении алгоритма. Примечание. Ускорение метода реального времени по сравнению с методом КМП состоит в том, что при обнаружении несовпадения символов P[i + 1] и T[t] выполняется сдвиг строки P вправо на i − spi,T[t](P) − 1 позиций; при этом не требуется выполнять повторное сравнение символа строки P, совмещенного с прежней текущей позицией t строки T, и можно сразу переходить к сравнению следующей пары символов.
Match37°. Дана строка P и набор значений Zi(P), i = 2, …, |P| (см. Match9). Кроме того, дано число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Найти значения spi,x(P) (см. Match35), модифицировав быстрый алгоритм нахождения sp'i(P), описанный в Match26: • вначале все значения spi,x(P) полагаются равными −1, а все значения sp'i(P) равными 0; • в цикле по j от |P| до 2 с шагом −1 значения spi,x(P) и sp'i(P) полагаются равными Zj(P), где i = j + Zj(P) − 1, x = P[Zj(P) + 1]; • если после завершения цикла значение sp|P|,P[1](P) остается равным −1, то оно заменяется на 0; • значения spi,x(P) в случае x = P[i + 1] определяются по формулам: spn−1,P[n](P) = sp'n(P) − 1, где n = |P|; spi−1,P[i](P) = max{spi,P[i+1](P), sp'i(P)} − 1, где i изменяется от |P| − 1 до 2 с шагом −1. Вывести найденные значения spi,x(P), перебирая x из Σ в алфавитном порядке и для каждого x изменяя i от 1 до |P|. Примечание. В первом цикле описанного алгоритма определяются значения spi,x(P) в случае x ≠ P[i + 1]. Рекуррентные формулы для spi,x(P) в случае x = P[i + 1] можно получить из соотношения spi−1,P[i](P) = spi(P) − 1, i = 2, …, |P|, с учетом алгоритма вычисления spi, приведенного в Match27.
Match38°. Даны строки P, T и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Используя метод реального времени (см. Match36), найти все вхождения P в T. Для вычисления spi,x(P) использовать быстрый алгоритм основного препроцессинга (см. Match16) и алгоритм, описанный в Match37. Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также значения spi,x(P), i = 1, …, |P|, x = «a», и количество сравнений символов, потребовавшееся при выполнении алгоритма (в том числе и при выполнении основного препроцессинга).
Правила сдвига по плохому символу и по хорошему суффиксу
Match39°. Дана строка P и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Через Rx(P) обозначается позиция крайнего правого вхождения символа x в строку P (если x не входит в P, то Rx(P) = 0). Выполняя однократный просмотр символов строки P и не используя условные операторы, найти Rx(P) для x из Σ и вывести найденные значения, перебирая x в алфавитном порядке.
Match40°. Дана строка P и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Через Rx,i(P), i = 1, …, |P|, обозначается позиция ближайшего вхождения символа x в строку P слева от позиции i (или 0, если требуемые вхождения отсутствуют). Организовав хранение значений Rx,i(P) в двумерном массиве и не используя условные операторы, найти Rx,i(P) для x из Σ и вывести найденные значения, перебирая x в алфавитном порядке и для каждого x изменяя i от 1 до |P|.
Match41°. Даны строки P, T и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Вычислить значения Rx(P) для x из Σ (см. Match39) и найти все вхождения P в T, используя посимвольное сравнение строк справа налево, а также правило сдвига по плохому символу. Для этого использовать переменную k, инициализировав ее значением |P|, и переменные p и t, хранящие текущие позиции строк P и T соответственно. Пока выполняется условие k ≤ |T|, выполнять следующие действия: • положить p равной |P|, а t равной k; • пока p > 0 и P[p] = T[t], уменьшать на 1 переменные p и t; • равенство p = 0 означает, что обнаружено очередное вхождение P в T (начиная с позиции t + 1), в этом случае увеличить k на 1; в противном случае увеличить k на max{1, p − Rx(P)}, где в качестве x указывается T[t]. Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также значения Rx(P) для x из Σ (перебирая x в алфавитном порядке) и количество сравнений символов, потребовавшееся при выполнении алгоритма. Примечание. Ускорение в методе, использующем правило сдвига по плохому символу (по сравнению с наивным алгоритмом поиска) достигается за счет того, что изменение значения k (интерпретируемое как сдвиг образца P вправо относительно текста T) может выполняться на величину, большую 1. А именно, если крайнее правое вхождение в P символа T[t] занимает позицию j, расположенную слева от текущей позиции P, то строка P сдвигается вправо таким образом, чтобы символ P[j] совместился с T[t]. Особенно эффективен такой сдвиг в случае, если T[t] не входит в строку-образец P (в этом случае j = 0, и начальная позиция строки P сразу совмещается с позицией t + 1 строки T).
Match42°. Даны строки P, T и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Вычислить значения Rx,i(P) для x из Σ (см. Match40) и найти все вхождения P в T, используя посимвольное сравнение строк справа налево и расширенное правило сдвига по плохому символу. Данное правило отличается от обычного правила сдвига по плохому символу (см. Match41) тем, что при увеличении переменной k вместо выражения p − RT[t](P) используется выражение p − RT[t],p(P). Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также значения Rx,i(P), x = «a», i = 1, …, |P|, и количество сравнений символов, потребовавшееся при выполнении алгоритма. Примечание. Расширенное правило плохого символа более эффективно (по сравнению с обычным правилом) при обработке строк, содержащих большое количество повторяющихся символов.
Match43°. Дана строка P и число i (≤ |P|). Через Li(P) обозначается наибольшая позиция в P, меньшая |P| и такая, что подстрока P[i..|P|] совпадает с суффиксом строки P[1..Li(P)]. Если такой позиции нет, то Li(P) = 0. Иначе говоря, Li(P) определяет позицию правого конца крайней правой копии строки P[i..|P|], которая не является суффиксом P. Найти и вывести Li(P).
Match44°. Дана строка P и число k (≤ |P|). Через L'i(P), i = 2, …, |P|, обозначается наибольшая позиция в P, меньшая |P| и такая, что подстрока P[i..|P|] совпадает с суффиксом строки P[1..L'i(P)], причем символ, предшествующий этому суффиксу, либо отсутствует, либо не равен P[i − 1]. Если такой позиции нет, то L'i(P) = 0. В случае i = 1 по определению полагается L'1(P) = 0. Таким образом, L'i(P) ≤ Li(P) (см. Match43). Найти и вывести L'i(P) для i = 1, …, |P|.
Match45°. Дана строка P. Через si(P), i = 1, …, |P|, обозначается длина наибольшего суффикса подстроки P[i..|P|], который является собственным префиксом P. Если таких суффиксов не существует, то si(P) = 0. Найти и вывести si(P) для i = 1, …, |P|.
Match46°. Даны строки P и T, а также значения Li(P) и si(P), i = 1, …, |P| (см. Match43 и Match45). Найти все вхождения P в T, используя посимвольное сравнение справа налево и слабое правило сдвига по хорошему суффиксу. Для этого использовать схему алгоритма, реализующего правило сдвига по плохому символу (см. Match41), изменив его заключительное действие следующим образом: • если p = 0, т. е. обнаружено очередное вхождение P в T (начиная с позиции t + 1), то увеличить k на |P| − s2(P); в противном случае, если p = |P|, то увеличить k на 1, а если p < |P|, то в случае Lp+1(P) > 0 увеличить k на |P| − Lp+1(P), а в случае Lp+1(P) = 0 увеличить k на |P| − sp+1(P). Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также количество сравнений символов, потребовавшееся при выполнении алгоритма. Примечание. Приведем словесное описание слабого правила сдвига по хорошему суффиксу: если обнаружена подстрока T' из T, совпадающая с суффиксом P и такая, что символы слева от этих подстрок не совпадают, то в P ищется крайняя правая подстрока P', совпадающая с T' и не являющаяся суффиксом P, после чего P сдвигается вправо так, чтобы подстрока P' строки P совместилась с подстрокой T' строки T. Если требуемая подстрока P' отсутствует (ситуация Lp+1(P) = 0), то выполняется наименьший сдвиг P вправо, при котором префикс сдвинутой строки P совпадет с некоторым суффиксом подстроки T' в T (если такого сдвига не существует, то P сдвигается на |P| позиций вправо). При обнаружении вхождения P выполняется наименьший сдвиг вправо, при котором собственный префикс сдвинутой строки P совпадет с некоторым суффиксом найденного вхождения P в T (если такого сдвига не существует, то P сдвигается на |P| позиций вправо).
Match47°. Даны строки P и T, а также значения L'i(P) и si(P), i = 1, …, |P| (см. Match44 и Match45). Найти все вхождения P в T, используя посимвольное сравнение справа налево и сильное правило сдвига по хорошему суффиксу, отличающееся от слабого правила (см. Match46) тем, что при увеличении переменной k вместо значений Lp+1(P) используются значения L'p+1(P). Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также количество сравнений символов, потребовавшееся при выполнении алгоритма. Примечание. Сильное правило сдвига по хорошему суффиксу отличается от слабого тем, что если обнаружена подстрока T' из T, совпадающая с суффиксом P, и такая, что символы слева от этих подстрок не совпадают, то в P ищется крайняя правая подстрока P', не только совпадающая с T', но и обладающая дополнительным свойством: символ слева от P' не равен символу слева от суффикса строки P, равного T'.
Match48°. Дана строка P и число i (< |P|). Через Ni(P), i = 1, …, |P| − 1, обозначается длина наибольшего суффикса строки P[1..i], который также является суффиксом полной строки P. Если такого суффикса нет, то Ni(P) = 0. Найти и вывести Ni(P).
Match49°. Дана строка P. Реализовать следующий алгоритм вычисления значений Ni(P) (см. Match48): • инвертировать строку P, получив в результате строку P'; • используя быстрый алгоритм основного препроцессинга для строки P' (см. Match16), найти значения Zj(P'), j = 2, …, |P|; • положить значение Ni(P) равным Z|P|−i+1(P'), i = 1, …, |P| − 1. Вывести найденные значения Ni(P) для i = 1, …, |P| − 1. Вывести также количество сравнений символов, потребовавшееся при выполнении основного препроцессинга.
Match50°. Дано число n и набор значений Ni(P), i = 1, …, n − 1, для некоторой строки P длины n (см. Match48). Найти значения L'i(P) для i = 1, …, n (см. Match44), используя соотношение L'i(P) = j, где j < n — наибольший индекс, такой что i = n − Nj(P) + 1 (если требуемые индексы j отсутствуют, то L'i(P) = 0). Перебор j организовать в цикле от 1 до n − 1 с шагом 1, условные операторы не использовать. Вывести найденные значения L'i(P).
Match51°. Дано число n и набор значений Ni(P), i = 1, …, n − 1, для некоторой строки P длины n (см. Match48). Найти значения Li(P) для i = 1, …, n (см. Match43), используя формулы для L'i(P), приведенные в Match50, а также соотношения L1(P) = 0, Li(P) = max{Li−1(P), L'i(P)}, i = 2, …, n. Вывести найденные значения Li(P).
Match52°. Дано число n и набор значений Ni(P), i = 1, …, n − 1, для некоторой строки P длины n (см. Match48). Найти значения si(P) для i = 1, …, n (см. Match45), используя соотношение si(P) = j, где j ≤ n − i + 1 — наибольший индекс, такой что Nj(P) = j (если требуемые индексы j отсутствуют, то si(P) = 0). Алгоритм не должен содержать вложенных циклов (ср. с Match51). Вывести найденные значения si(P).
Метод Бойера–Мура
Match53°. Даны строки P, T и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Также даны значения Rx(P) для x из Σ (см. Match39, символы x перебираются в алфавитном порядке) и значения Li(P) и si(P), i = 1, …, |P| (см. Match43 и Match45). Найти все вхождения P в T, используя вариант метода Бойера–Мура, совместно применяющий правило сдвига по плохому символу (см. Match41) и слабое правило сдвига по хорошему суффиксу (см. Match46). Для этого использовать схему алгоритма, применяющего слабое правило сдвига по хорошему суффиксу, дополнив его заключительное действие следующим образом: • если p > 0, т. е. вхождение P в T не обнаружено, то увеличить k на max{s, p − RT[t](P)}, где s — величина сдвига, вычисленная по слабому правилу хорошего суффикса. Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также количество сравнений символов, потребовавшееся при выполнении алгоритма.
Match54°. Даны строки P, T и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Также даны значения Rx(P) для x из Σ (см. Match39, символы x перебираются в алфавитном порядке) и значения L'i(P) и si(P), i = 1, …, |P| (см. Match44 и Match45). Найти все вхождения P в T, используя вариант метода Бойера–Мура, совместно применяющий правило сдвига по плохому символу (см. Match41) и сильное правило сдвига по хорошему суффиксу (см. Match47). Для этого использовать схему алгоритма, применяющего сильное правило сдвига по хорошему суффиксу, дополнив его заключительное действие следующим образом: • если p > 0, т. е. вхождение P в T не обнаружено, то увеличить k на max{s, p − RT[t](P)}, где s — величина сдвига, вычисленная по сильному правилу хорошего суффикса. Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также количество сравнений символов, потребовавшееся при выполнении алгоритма.
Match55°. Даны строки P, T и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Также даны значения Rx,i(P) для x из Σ (см. Match40, символы x перебираются в алфавитном порядке, для каждого x значение i меняется от 1 до |P|) и значения Li(P) и si(P), i = 1, …, |P| (см. Match43 и Match45). Найти все вхождения P в T, используя вариант метода Бойера–Мура, совместно применяющий расширенное правило сдвига по плохому символу (см. Match42) и слабое правило сдвига по хорошему суффиксу (см. Match46). Для этого использовать схему алгоритма, применяющего слабое правило сдвига по хорошему суффиксу, дополнив его заключительное действие следующим образом: • если p > 0, т. е. вхождение P в T не обнаружено, то увеличить k на max{s, p − RT[t],p(P)}, где s — величина сдвига, вычисленная по слабому правилу хорошего суффикса. Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также количество сравнений символов, потребовавшееся при выполнении алгоритма.
Match56°. Даны строки P, T и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Также даны значения Rx,i(P) для x из Σ (см. Match40, символы x перебираются в алфавитном порядке, для каждого x значение i меняется от 1 до |P|) и значения L'i(P) и si(P), i = 1, …, |P| (см. Match44 и Match45). Найти все вхождения P в T, используя вариант метода Бойера–Мура, совместно применяющий расширенное правило сдвига по плохому символу (см. Match42) и сильное правило сдвига по хорошему суффиксу (см. Match47). Для этого использовать схему алгоритма, применяющего сильное правило сдвига по хорошему суффиксу, дополнив его заключительное действие следующим образом: • если p > 0, т. е. вхождение P в T не обнаружено, то увеличить k на max{s, p − RT[t],p(P)}, где s — величина сдвига, вычисленная по сильному правилу хорошего суффикса. Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также количество сравнений символов, потребовавшееся при выполнении алгоритма.
Match57°. Даны строки P, T и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Найти все вхождения P в T, используя вариант метода Бойера–Мура, совместно применяющий правило сдвига по плохому символу и слабое правило сдвига по хорошему суффиксу (см. Match53). Для вычисления значений Li(P) и si(P) использовать быстрый алгоритм препроцессинга, описанный в Match49–Match52). Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также значения Rx(P), перебирая x из Σ в алфавитном порядке, и количество сравнений символов, потребовавшееся при выполнении алгоритма (в том числе и при проведении препроцессинга).
Match58°. Даны строки P, T и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Найти все вхождения P в T, используя вариант метода Бойера–Мура, совместно применяющий правило сдвига по плохому символу и сильное правило сдвига по хорошему суффиксу (см. Match54). Для вычисления значений L'i(P) и si(P) использовать быстрый алгоритм препроцессинга, описанный в Match49, Match50, Match52). Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также значения si(P), i = 1, …, |P|, и количество сравнений символов, потребовавшееся при выполнении алгоритма (в том числе и при проведении препроцессинга).
Match59°. Даны строки P, T и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Найти все вхождения P в T, используя вариант метода Бойера–Мура, совместно применяющий расширенное правило сдвига по плохому символу и слабое правило сдвига по хорошему суффиксу (см. Match55). Для вычисления значений Li(P) и si(P) использовать быстрый алгоритм препроцессинга, описанный в Match49–Match52). Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также значения Li(P), i = 1, …, |P|, и количество сравнений символов, потребовавшееся при выполнении алгоритма (в том числе и при проведении препроцессинга).
Match60°. Даны строки P, T и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Найти все вхождения P в T, используя вариант метода Бойера–Мура, совместно применяющий расширенное правило сдвига по плохому символу и сильное правило сдвига по хорошему суффиксу (см. Match56). Для вычисления значений L'i(P) и si(P) использовать быстрый алгоритм препроцессинга, описанный в Match49, Match50, Match52). Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также значения L'i(P), i = 1, …, |P|, и количество сравнений символов, потребовавшееся при выполнении алгоритма (в том числе и при проведении препроцессинга).
Битовый метод поиска точных и неточных вхождений
Match61°. Даны строки P, T (|P| < 32) и число j (0 ≤ j ≤ |T|). Через M(P, T) обозначается битовая матрица размера |P| × (|T| + 1), элементы которой Mi,j(P, T), i = 1, …, |P|, j = 0, …, |T|, равны 1, если первые i символов P совпадают с i символами T, кончающимися на позиции j (т. е. P[1..i] = T[j−i+1..j]), и равны 0 в противном случае. Через Mj(P, T) обозначается j-й столбец матрицы M(P, T). Для данных P и T сформировать столбец Mj(P, T) и получить его числовое представление, т. е. представление в виде целого числа, двоичная запись которого (дополненная слева нулями до |P| разрядов) совпадает с элементами вектора Mj(P, T), перебираемыми в порядке возрастания индексов (например, вектор-столбцу (0, 1, 1)T соответствует числовое представление 3). Вывести элементы столбца Mj(P, T) и соответствующее ему числовое представление. Примечание. Элементы матрицы M(P, T), равные 1 в строчке i, показывают все позиции в T, где заканчивается копия подстроки P[1..i], поэтому по последней строчке матрицы M можно определить завершающие позиции всех вхождений P в T.
Match62°. Дана строка P (|P| < 32) и число k (≤ |P|). Через U(x, P), где x — некоторый символ, обозначается битовый вектор длины |P|, для которого Ui(x, P) = 1, если P[i] = x, и Ui(x, P) = 0 в противном случае. Для данной строки P найти вектор U(P[k], P) и вывести его элементы, а также соответствующее ему числовое представление (определение числового представления дано в Match61).
Match63°. Дана строка P (|P| < 32) и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Для каждого символа x из Σ найти числовое представление вектора U(x, P) (см. Match62) и вывести эти представления, перебирая x в алфавитном порядке. Для хранения числовых представлений векторов использовать массив. Сформировать все числовые представления за однократный просмотр строки, вложенные циклы не использовать.
Match64°. Даны числа v и p; p = 2n для некоторого n > 0, v является числовым представлением некоторого вектора V длины n (определение числового представления дано в Match61). Через RShift(V) обозначается вектор V', полученный из вектора V сдвигом всех его элементов на 1 позицию в направлении увеличения индексов, причем первый элемент вектора V' полагается равным 1, а последний элемент вектора V теряется. Используя арифметические и побитовые операции над целыми числами и не применяя циклы, найти числовые представления векторов RShift(V) и RShift(RShift(V)). Оформить вычисление числового представления RShift(V) в виде вспомогательной функции с параметрами v и p.
Match65°. Дана строка T и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Также даны характеристики некоторой строки P: ее длина n и числовые представления векторов U(x, P) для всех x из Σ (см. Match62, символы x перебираются в алфавитном порядке). Найти столбцы матрицы M(P, T) (см. Match61), используя следующий алгоритм: • столбец M0 является нулевым; • для любого j > 0 столбец Mj вычисляется по формуле Mj = RShift(Mj−1) and U(T[j], P) (операция RShift описана в Match64). Все вычисления проводить над числовыми представлениями векторов; при нахождении матрицы M хранить только два ее столбца: вычисляемый и найденный на предыдущем шаге. В процессе вычисления столбцов Mj, j = 1, …, |T|, выводить их числовые представления. Примечание. Формула отражает тот факт, что i-й элемент столбца Mj будет равен 1 тогда и только тогда, когда подстрока P[1..i − 1] совпадет с подстрокой T той же длины, оканчивающейся в позиции j − 1 (в этом случае i-й элемент вектора RShift(Mj−1) будет равен 1), и, кроме того, символ P[i] совпадет с T[j] (в этом случае i-й элемент вектора U(T[j], P) также будет равен 1).
Match66°. Даны строки P, T (|P| < 32) и число m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Известно, что имеется хотя бы одно вхождение образца P в текст T. Найти все вхождения P в T, используя битовый метод поиска. Для этого сформировать векторы U(x, P) для всех x из Σ (см. Match63), после чего организовать последовательное вычисление столбцов матрицы M(P, T) (см. Match65). Вхождения P в T определять, анализируя последние элементы столбцов Mj(P, T) (см. примечание к Match61; для числовых представлений столбцов достаточно проанализировать их четность). Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), а также числовые представления U(x, P), перебирая x из Σ в алфавитном порядке, и числовое представление столбцов Mj(P, T), соответствующих конечным позициям j найденных вхождений (числовые представления всех этих столбцов будут одинаковыми).
Match67°. Даны строки P, T (|P| < 32) и числа k (k ≤ 5) и j (0 ≤ j ≤ |T|). Через Mk(P, T), k ≥ 0, обозначается битовая матрица размера |P| × (|T|+1), элементы которой Mki,j(P, T), i = 1, …, |P|, j = 0, …, |T|, равны 1, если не менее i − k из первых i символов P совпадают с соответствующими символами из i символов T, кончающихся на позиции j (т. е. P[1..i] отличается от T[j − i + 1..j] не более чем в k позициях). В противном случае Mki,j(P, T) = 0. Через Mkj(P, T) обозначается j-й столбец матрицы Mk(P, T). Для данных P и T сформировать столбец Mkj и получить его числовое представление (определение числового представления приведено в Match61). Вывести элементы столбца Mkj и соответствующее ему числовое представление. Примечание. Единичные элементы строки матрицы Mk(P, T) с номером |P| соответствуют завершающим позициям всех неточных вхождений P в T с не более чем k несовпадающими символами (называемых также вхождениями с не более чем k ошибками).
Match68°. Дана строка T и числа k (≤ 5) и m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Также даны характеристики некоторой строки P: ее длина n и числовые представления векторов U(x, P) для всех x из Σ (см. Match62, символы x перебираются в алфавитном порядке). Для данного k найти столбцы матрицы Mk(P, T) (см. Match67), используя следующий алгоритм: • при фиксированном j = 0, …, |T| последовательно вычисляются Mqj для q = 0, …, k; • для любого q столбец Mq0 является нулевым; • столбец M0j вычисляется по формуле M0j = RShift(M0j−1) and U(T[j], P) (операция RShift описана в Match64); • для j > 0 столбец Mqj вычисляется по формуле Mqj = RShift(Mq−1j−1) or (RShift(Mqj−1) and U(T[j], P)). Все вычисления проводить над числовыми представлениями векторов; при нахождении матриц Mq хранить только два набора их столбцов: вычисляемый Mqj и найденный на предыдущем шаге Mqj−1. В процессе вычисления столбцов Mkj, j = 1, …, |T|, выводить их числовые представления. Примечание. Формула для вычисления Mqj при положительных q и j отражает тот факт, что i первых символов строки P и i символов строки T, оканчивающихся в позиции j, будут иметь не более q несовпадений в том и только том случае, если i − 1 первых символов строки P и i − 1 символов строки T, оканчивающихся в позиции j − 1, будут иметь не более q − 1 несовпадений (эту ситуацию проверяет операнд RShift(Mq−1j−1) либо i − 1 первых символов строки P и i − 1 символов строки T, оканчивающихся в позиции j − 1, будут иметь не более q несовпадений и при этом пара символов P[i] и T[j] будет совпадать (эту ситуацию проверяет операнд RShift(Mqj−1) and U(T[j], P)).
Match69°. Даны строки P, T (|P| < 32) и числа k (≤ 5) и m (< 10); алфавит Σ представляет собой m первых строчных латинских букв. Известно, что имеется хотя бы одно вхождение образца P в текст T, содержащее не более k несовпадений. Найти все такие вхождения P в T, используя битовый метод неточного поиска. Для этого сформировать векторы U(x, P) для всех x из Σ (см. Match62), после чего организовать последовательное вычисление столбцов матрицы Mk(P, T) (см. Match68). Неточные вхождения P в T определять, анализируя последние элементы столбцов Mkj (см. примечание к Match67; для числовых представлений столбцов достаточно проанализировать их четность). Для каждого найденного неточного вхождения P в T выводить его начальную позицию и числовое представление Mkj, где j — номер конечной позиции данного вхождения. Вхождения перебирать в порядке возрастания их начальных позиций.
Метод дактилограмм Карпа–Рабина
Match70°. Дана строка S, состоящая из символов «0» и «1» (|S| < 32). Через H(S) обозначается число, строковое представление которого в двоичной системе счисления совпадает со строкой S: H(S) = Σi=1|S| 2|S|−i·d(S[i]), где d(«0») = 0, d(«1») = 1. Найти Н(S), используя схему Горнера: H(S) = (…(((d(S[1])·2 + d(S[2]))·2 + d(S[3]))·2 + d(S[4]))…)·2 + d(S[|S|]).
Match71°. Дана строка T, состоящая из символов «0» и «1», число n (< min{|T|, 31}) и значение H(T[1..n]) (см. Match70). Найти и вывести значения H(Tnk), k = 2, …, |T| − n + 1, где Tnk = T[k..k + n − 1] — подстрока строки T, имеющая длину n и начинающаяся в позиции k. Для вычисления H(Tnk) использовать рекуррентную формулу: H(Tnk) = H(Tnk−1)·2 − d(T[k − 1])·2n + d(T[k + n − 1]).
Match72°. Даны строки P и T, состоящие из символов «0» и «1», |P| < 31. Найти все вхождения P в T, сравнивая значения H(P) и H(Tnk), k = 1, …, |T| − n + 1, где n = |P| (определение H(S) дано в Match70, обозначение Tnk и быстрый алгоритм вычисления H(Tnk) приведены в Match71). Строка P входит в T, начиная с позиции k, тогда и только тогда, когда H(P) = H(Tnk). Вывести H(P), H(Tn1) и начальные позиции всех найденных вхождений P в T (в порядке возрастания), после чего дополнительно вывести H(Tn|T|−n+1).
Match73°. Дана строка S, состоящая из символов «0» и «1», и число q. Через Hq(S) обозначается число, равное Н(S) mod q, где число H(S) определено в Match70, а «mod» обозначает операцию взятия остатка от деления нацело. Значение Hq(S) лежит в диапазоне от 0 до q − 1 и называется дактилограммой строки S. Найти Нq(S), используя вариант схемы Горнера, в котором ни один результат умножения не превосходит 2·q: Hq(S) = ((…(((d(S[1])·2 mod q + d(S[2]))·2 mod q + d(S[3]))·2 mod q + d(S[4]))…)·2 mod q + d(S[|S|])) mod q. Вывести промежуточные результаты вычислений, полученные перед каждой операцией умножения на 2, а также найденное значение Hq(S).
Match74°. Дана строка T, состоящая из символов «0» и «1», числа n (< |T|) и q, а также значение Hq(T[1..n]) (см. Match73). Найти и вывести значения Hq(Tnk), k = 2, …, |T| − n + 1 (обозначение Tnk описано в Match71). Для вычисления Hq(Tnk) использовать рекуррентную формулу: Hq(Tnk) = (Hq(Tnk−1)·2 − d(T[k − 1])·(2n mod q) + d(T[k + n − 1]) + q) mod q. Для вычисления 2n mod q использовать схему, в которой промежуточные результаты не превосходят 2·q: 2n mod q = 2·(…(2·(2·2 mod q) mod q)…) mod q.
Match75°. Даны строки P и T, состоящие из символов «0» и «1», и число q. Найти все вхождения P в T используя метод дактилограмм Карпа–Рабина. Для этого найти и сравнить значения Hq(P) и Hq(Tnk), k = 1, …, |T| − n + 1, где n = |P| (определение Hq(S) дано в Match73, обозначение Tnk — в Match71, быстрый алгоритм вычисления Hq(Tnk) — в Match74). Если Hq(P) = Hq(Tnk), то строка P, возможно, входит в T, начиная с позиции k; в этом случае надо провести дополнительное сравнение символов в порядке слева направо до первого несовпадения символов (случай ложного совпадения) или до успешного подтверждения обнаруженного вхождения. Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), после чего дополнительно вывести общее количество выполненных сравнений символов и количество выявленных ложных совпадений.
Match76°. Дана строка S (|S| < 10) и число m (1 < m < 10); алфавит представляет собой m первых цифр («0», «1», «2», …). Через Hm(S) обозначается число, строковое представление которого в m-ичной системе счисления совпадает со строкой S: Hm(S) = Σi=1|S| m|S|-i·d(S[i]), где d(«0») = 0, d(«1») = 1, d(«2») = 2, … . Найти Нm(S), используя схему Горнера: H(S) = (…(((d(S[1])·m + d(S[2]))·m + d(S[3]))·m + d(S[4]))…)·m + d(S[|S|]).
Match77°. Дана строка S и числа q и m (1 < m ≤ 10); алфавит представляет собой m первых цифр. Через Hmq(S) обозначается число, равное Нm(S) mod q, где Hm(S) определено в Match76, а «mod» обозначает операцию взятия остатка от деления нацело. Найти Нmq(S), используя вариант схемы Горнера, в котором ни один результат умножения не превосходит m·(q + m − 2): Hmq(S) = ((…(((d(S[1])·m mod q + d(S[2]))·m mod q + d(S[3]))·m mod q + d(S[4]))…)·m mod q + d(S[|S|])) mod q. Вывести промежуточные результаты вычислений, полученные перед каждой операцией умножения на m, а также найденное значение Hmq(S).
Match78°. Дана строка T, числа n (< |T|), q и m (1 < m ≤ 10); алфавит представляет собой m первых цифр. Кроме того, дано значение Hmq(T[1..n]) (см. Match77). Найти и вывести значения Hmq(Tnk), k = 2, …, |T| − n + 1 (обозначение Tnk определено в Match71). Для вычисления Hmq(Tnk) использовать рекуррентную формулу: Hmq(Tnk) = (Hmq(Tnk−1)·m − d(T[k − 1])·(mn mod q) + d(T[k + n − 1]) + (m − 1)·q) mod q. Для вычисления mn mod q использовать схему, в которой промежуточные результаты не превосходят m·q: mn mod q = m·(…((m·(m mod q) mod q))…) mod q.
Match79°. Даны строки P, T и числа q и m (1 < m ≤ 10); алфавит представляет собой m первых цифр. Найти все вхождения P в T используя вариант метода дактилограмм Карпа–Рабина (см. Match75), в котором применяются дактилограммы Hmq(S) (см. Match77–Match78). Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), после чего дополнительно вывести общее количество сравнений символов и количество выявленных ложных совпадений.
Match80°. Даны строки P, T и числа q и m (1 < m ≤ 26); алфавит представляет собой m первых строчных латинских букв. Найти все вхождения P в T используя вариант метода дактилограмм Карпа–Рабина (см. Match75), в котором применяются дактилограммы Hmq(S) (см. Match77–Match78), причем d(«a») = 0, d(«b») = 1, d(«c») = 2, …, d(«k») = 10, … . Вывести начальные позиции всех найденных вхождений P в T (в порядке возрастания), после чего дополнительно вывести общее количество сравнений символов и количество выявленных ложных совпадений.
|