Подтема 3 из 7
Образцы и блоки
Повторяющийся образец вроде DOGDOG…, цепочки пар и троек со смещением, короткие фрагменты и палиндромы.
Повторяющийся образец
Как найти самую длинную цепочку вида DOGDOGDOGD…, если последний кусок может быть неполным?
Помнить, сколько символов цепочки уже набрано: следующим должен идти pattern[current % 3]. Совпал — цепочка растёт. Не совпал — новая цепочка может начаться, только если это D. После 0, 3, 6 набранных символов снова ждём D, после 1, 4, 7 — O: остаток от деления на длину образца повторяется.
В строке 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)Тонкости:образец с повторяющейся буквой и только целые блоки
Перезапуск «с первой буквы образца» верен, когда эта буква встречается в образце один раз, как 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)Цепочка 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)Самая длинная цепочка — 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)С нулевой позиции пары CA, BC, BA, BA — ни одной подходящей. С первой — 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)Подходят ABCBA и BAXAB. Последнее начало — len(s) − 5, а правая граница range не входит, поэтому range(len(s) - 4). Так же проверяют любые условия на короткий кусок: «первый символ из A, B, C, второй из C, D, E, символы не повторяются» — это len(set(t)) == 3 и проверки по позициям.
Вхождения слова тоже ищут перебором начал. Метод здесь не годится: найдя слово, он продолжает поиск после его конца и пропускает перекрытия.
Итого
- Образец
c == pattern[current % m] - Не совпал1, если это первая буква образца, иначе 0
- С любого местапроверка пары «за этой буквой — следующая»
- Пары, тройкишаг 2 или 3, все смещения
- Короткий кусокперебор начал: s[i:i + k]
- Перекрытияcount их не видит — перебирай начала
Проверьте себя
Ответь сначала сам, потом открой ответ.
ОтветСкрыть ответ
ОтветСкрыть ответ
'ABABAB'.count('ABA')?ОтветСкрыть ответ
ОтветСкрыть ответ
ОтветСкрыть ответ
Практика
Для проверки ответов нужен JavaScript. Условия, подсказки и решения доступны ниже.
Цепочка ABCABC…
В ABABCABCA найди максимальную цепочку вида ABCABC..., начинающуюся с A. Неполный последний блок разрешён.
Введите число.
Подсказка
Длина цепочки показывает, какая буква образца ожидается следующей.
Решение
7: ABCABCA с позиции 2.
Решение программой
s = 'ABABCABCA'pattern = 'ABC'current = best = 0for c in s: if c == pattern[current % len(pattern)]: current += 1 elif c == pattern[0]: current = 1 else: current = 0 best = max(best, current)print(best)Ответ: 7
Цепочка XYZXYZ…
Текстовый файл 24-1.txt состоит из символов X, Y и Z. Определите максимальную длину цепочки вида XYZXYZ… (составленной из фрагментов XYZ, последний фрагмент может быть неполным), которая начинается с буквы X.
Введите число.
Подсказка
Если символ не тот, что ожидается, но равен X, цепочка начинается заново с длины 1.
Решение
51: цепочка, которая начинается с Y, сама не подходит; подходит её часть с первой буквы X.
Решение программой
s = open('24-1.txt').readline().strip() pattern = 'XYZ'current = best = 0for c in s: if c == pattern[current % len(pattern)]: current += 1 elif c == pattern[0]: current = 1 else: current = 0 best = max(best, current)print(best)Ответ: 51
Группы SQRP с любого места
Строка PSQRPSQRXSQRPSQ состоит из символов P, Q, R, S и X. Найди максимальное количество символов в цепочке из идущих подряд групп SQRP; в начале и в конце цепочки группа может быть неполной.
Введите число.
Подсказка
За S идёт Q, за Q — R, за R — P, за P — S: это условие на пару, сброс до 1.
Решение
8: PSQRPSQR, X обрывает цепочку.
Решение программой
s = 'PSQRPSQRXSQRPSQ'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)Ответ: 8
Пары «согласная + гласная»
В строке BABEDACA найди самую длинную цепочку пар «согласная + гласная» (согласные BCDF, гласные AE). Сколько в ней пар и символов?
Введите два числа через пробел: количество пар и количество символов.
Подсказка
Пары идут целиком: проверь оба смещения, 0 и 1.
Решение
4 пары, 8 символов: BA BE DA CA с позиции 0.
Решение программой
s = 'BABEDACA'best = 0for offset in range(2): current = 0 for i in range(offset, len(s) - 1, 2): if s[i] in 'BCDF' and s[i + 1] in 'AE': current += 1 else: current = 0 best = max(best, current)print(best, 2 * best)Ответ: 4 8
Пары AB и CB подряд
Найди максимальное количество идущих подряд пар символов AB или CB в строке CBABXABCBAB. Пары могут идти в любом порядке.
Введите число.
Подсказка
Пары идут целиком: проверь оба смещения, 0 и 1.
Решение
3: AB, CB, AB с первой позиции.
Решение программой
s = 'CBABXABCBAB'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)Ответ: 3
Пары «гласная + согласная»
Текстовый файл 24-4.txt содержит заглавные латинские буквы. Гласными считаются A, E, I, O, U, Y, остальные буквы — согласные. Определите максимальное количество идущих подряд пар символов вида «гласная + согласная».
Введите число.
Подсказка
Пары идут целиком: проверь оба смещения.
Решение
9: проверяются оба смещения.
Решение программой
s = open('24-4.txt').readline().strip() vowels = 'AEIOUY'best = 0for offset in range(2): current = 0 for i in range(offset, len(s) - 1, 2): if s[i] in vowels and s[i + 1] not in vowels: current += 1 else: current = 0 best = max(best, current)print(best)Ответ: 9
Перекрывающиеся ABA
Посчитай все вхождения ABA в ABABABA, разрешая перекрытия.
Введите число.
Подсказка
Перебери каждое начало: count перекрытия не считает.
Решение
3: начала на позициях 0, 2, 4.
Решение программой
s = 'ABABABA'count = 0for i in range(len(s) - 2): if s[i:i + 3] == 'ABA': count += 1print(count)Ответ: 3
Одинаковые края тройки
Сколько троек с одинаковыми крайними символами в строке ABABBAB?
Введите число.
Подсказка
Тройка с началом i подходит, если s[i] == s[i + 2].
Решение
3: тройки ABA, BAB с позиции 1 и BAB с позиции 4.
Решение программой
s = 'ABABBAB'count = 0for i in range(len(s) - 2): if s[i] == s[i + 2]: count += 1print(count)Ответ: 3
Палиндромы длины 5
Текстовый файл 24-4.txt состоит не более чем из 10⁶ заглавных букв латинского алфавита. Определите количество непрерывных последовательностей длины 5, являющихся палиндромами — читающихся одинаково слева направо и справа налево.
Введите число.
Подсказка
Перебери все начала: кусок s[i:i + 5] — палиндром, если совпадает с t[::-1].
Решение
667 палиндромов.
Решение программой
s = open('24-4.txt').readline().strip()count = 0for i in range(len(s) - 4): t = s[i:i + 5] if t == t[::-1]: count += 1 print(count)Ответ: 667