К содержанию

Подтема 3 из 7

Образцы и блоки

Повторяющийся образец вроде DOGDOG…, цепочки пар и троек со смещением, короткие фрагменты и палиндромы.

Повторяющийся образец

Как найти самую длинную цепочку вида DOGDOGDOGD…, если последний кусок может быть неполным?

Помнить, сколько символов цепочки уже набрано: следующим должен идти pattern[current % 3]. Совпал — цепочка растёт. Не совпал — новая цепочка может начаться, только если это D. После 0, 3, 6 набранных символов снова ждём D, после 1, 4, 7 — O: остаток от деления на длину образца повторяется.

Набрано current символов — следующим ожидается pattern[current % 3]: после 0, 3 и 6 символов снова D.

В строке ODOGDOGDORDOG цепочка DOGDOGDO обрывается на R: там ждали G. R не может начать новую цепочку — current = 0. Следующая D начинает цепочку заново.

s = 'ODOGDOGDORDOG'pattern = 'DOG'current = 0best = 0for c in s:    if c == pattern[current % 3]:        current += 1    elif c == 'D':        current = 1    else:        current = 0    best = max(best, current) print(best)
8
Тонкости:образец с повторяющейся буквой и только целые блоки

Перезапуск «с первой буквы образца» верен, когда эта буква встречается в образце один раз, как D в DOG. Для образца AAB в строке AAAB при несовпадении нужно оставить две последние A, а не одну. Тогда проще проверить каждое возможное начало цепочки.

Если засчитываются только целые блоки, из ответа убирают неполный хвост: best - best % 3.

Начало с любого места

А если цепочка из групп SQRP может начинаться с любой буквы группы — RPSQRPS тоже подходит?

Тогда хватает проверки соседей: за S должна идти Q, за Q — R, за R — P, за P — S. Это условие на пару, и сброс — до 1, как в подтеме 2. Какая буква должна идти следом, удобно хранить в :

s = 'QRPSQRPSQXRPS'nxt = {'S': 'Q', 'Q': 'R', 'R': 'P', 'P': 'S'}current = 1best = 1for i in range(1, len(s)):    if nxt.get(s[i - 1]) == s[i]:        current += 1    else:        current = 1    best = max(best, current) print(best)
9

Цепочка QRPSQRPSQ — 9 символов, X её обрывает. nxt.get('X') вернёт None — у X следующей буквы нет. Если условие требует хоть одну полную группу SQRP, она точно есть в любой цепочке из 7 и больше символов.

Бывает, что на месте буквы допустимы два символа: в слове yandex вместо a можно писать 4, вместо e — 3. Тогда для каждого места храним набор допустимых символов и проверяем c in pattern[current % 6]:

s = 'qyandqqyand3xy4q'pattern = ['y', 'a4', 'n', 'd', 'e3', 'x']current = 0best = 0for c in s:    if c in pattern[current % 6]:        current += 1    elif c == 'y':        current = 1    else:        current = 0    best = max(best, current) print(best)
8

Самая длинная цепочка — yand3xy4: 3 стоит на месте e, 4 — на месте a.

Цепочки пар и троек

Сколько пар AB или CB идёт подряд? Например, в ABCBAB — три пары.

Пары не перекрываются, поэтому идём по строке шагом 2. Цепочка пар может начаться и на чётной, и на нечётной позиции — проверяем оба смещения. Третий аргумент range — шаг: range(1, 9, 2) даёт 1, 3, 5, 7.

s = 'CABCBABAB'best = 0for start in (0, 1):    current = 0    for i in range(start, len(s) - 1, 2):        if s[i:i + 2] in ('AB', 'CB'):            current += 1        else:            current = 0        best = max(best, current) print(best)
4

С нулевой позиции пары CA, BC, BA, BA — ни одной подходящей. С первой — AB, CB, AB, AB: четыре подряд.

Пары с позиций 0, 2, 4, 6 не подходят, а с позиций 1, 3, 5, 7 — AB, CB, AB, AB: четыре пары подряд.

Для троек вроде ABA или BAB шаг 3 и смещения три: 0, 1 и 2. Если спрашивают число символов, а не пар, ответ умножают на длину блока.

Бывает, что блок — любые символы набора: «RGB-цепочка — шесть шестнадцатеричных цифр». Тогда блоки друг от друга не отличаются, и число блоков подряд — это длина самой длинной цепочки таких символов, делённая на 6 нацело.

Короткие фрагменты

Сколько в строке фрагментов длины 5, которые читаются одинаково слева направо и справа налево — палиндромов?

Перебрать все начала: кусок s[i:i + 5] для i от 0 до len(s) − 5. Кусков около миллиона, но каждый короткий — это быстро. Кусок-палиндром совпадает со своим переворотом t[::-1].

s = 'ABCBAXABA'count = 0for i in range(len(s) - 4):    t = s[i:i + 5]    if t == t[::-1]:        count += 1 print(count)
2

Подходят ABCBA и BAXAB. Последнее начало — len(s) − 5, а правая граница range не входит, поэтому range(len(s) - 4). Так же проверяют любые условия на короткий кусок: «первый символ из A, B, C, второй из C, D, E, символы не повторяются» — это len(set(t)) == 3 и проверки по позициям.

Вхождения слова тоже ищут перебором начал. Метод здесь не годится: найдя слово, он продолжает поиск после его конца и пропускает перекрытия.

ABA в ABABA начинается с позиций 0 и 2. count находит первое вхождение и пропускает второе — оно перекрывается с первым.

Итого

  • Образецc == pattern[current % m]
  • Не совпал1, если это первая буква образца, иначе 0
  • С любого местапроверка пары «за этой буквой — следующая»
  • Пары, тройкишаг 2 или 3, все смещения
  • Короткий кусокперебор начал: s[i:i + k]
  • Перекрытияcount их не видит — перебирай начала

Проверьте себя

Ответь сначала сам, потом открой ответ.

Вопрос 1
В цепочке DOGDOG… уже набрано 7 символов. Какой символ ожидается следующим?
ОтветСкрыть ответ
Ответ
O: 7 % 3 = 1, а pattern[1] — O.
Вопрос 2
Почему для цепочки SQRP, которая может начинаться с любой буквы, при несовпадении сбрасывают до 1, а не до 0?
ОтветСкрыть ответ
Ответ
Любая из букв S, Q, R, P может начать новую цепочку, а условие — на пару соседей. Символ, на котором цепочка оборвалась, сам начинает новую.
Вопрос 3
Сколько вхождений ABA в строке ABABAB с перекрытиями? Что вернёт 'ABABAB'.count('ABA')?
ОтветСкрыть ответ
Ответ
Два — с позиций 0 и 2. count вернёт 1.
Вопрос 4
Сколько пар AB или CB идёт подряд в строке CBABXAB?
ОтветСкрыть ответ
Ответ
Две: CB и AB с нулевой позиции. С первой позиции подходит только AB в конце.
Вопрос 5
Сколько фрагментов длины 5 нужно проверить в строке из 1 000 000 символов?
ОтветСкрыть ответ
Ответ
999 996: начала с 0 по 999 995.

Практика

Для проверки ответов нужен JavaScript. Условия, подсказки и решения доступны ниже.

В ABABCABCA найди максимальную цепочку вида ABCABC..., начинающуюся с A. Неполный последний блок разрешён.

Введите число.

Текстовый файл 24-1.txt состоит из символов X, Y и Z. Определите максимальную длину цепочки вида XYZXYZ… (составленной из фрагментов XYZ, последний фрагмент может быть неполным), которая начинается с буквы X.

24-1.txtСтрока из символов X, Y и ZТекстовый файл · 195,3 КБ

Введите число.

Группы SQRP с любого места

Строка PSQRPSQRXSQRPSQ состоит из символов P, Q, R, S и X. Найди максимальное количество символов в цепочке из идущих подряд групп SQRP; в начале и в конце цепочки группа может быть неполной.

Введите число.

Пары «согласная + гласная»

В строке BABEDACA найди самую длинную цепочку пар «согласная + гласная» (согласные BCDF, гласные AE). Сколько в ней пар и символов?

Введите два числа через пробел: количество пар и количество символов.

Пары AB и CB подряд

Найди максимальное количество идущих подряд пар символов AB или CB в строке CBABXABCBAB. Пары могут идти в любом порядке.

Введите число.

Пары «гласная + согласная»

Текстовый файл 24-4.txt содержит заглавные латинские буквы. Гласными считаются A, E, I, O, U, Y, остальные буквы — согласные. Определите максимальное количество идущих подряд пар символов вида «гласная + согласная».

24-4.txtСтрока из заглавных латинских буквТекстовый файл · 293,0 КБ

Введите число.

Перекрывающиеся ABA

Посчитай все вхождения ABA в ABABABA, разрешая перекрытия.

Введите число.

Одинаковые края тройки

Сколько троек с одинаковыми крайними символами в строке ABABBAB?

Введите число.

Палиндромы длины 5

Текстовый файл 24-4.txt состоит не более чем из 10⁶ заглавных букв латинского алфавита. Определите количество непрерывных последовательностей длины 5, являющихся палиндромами — читающихся одинаково слева направо и справа налево.

24-4.txtСтрока из заглавных латинских буквТекстовый файл · 293,0 КБ

Введите число.