Подтема 5 из 7
Позиции и границы
Список позиций нужных символов: K подряд идущих вхождений, самый короткий и самый длинный фрагмент, особые начало и конец.
Список позиций
Нужен самый короткий фрагмент, в котором буква Q встречается 50 раз. С чего он начинается и чем кончается?
Он начинается на одной Q и кончается на 50-й Q, считая от неё: лишние символы по краям только удлинили бы его. Поэтому достаточно знать, где стоят все Q. Номера нужных букв собирает в список одна строка — . Если выбраны K подряд идущих букв — в списке это элементы с j по j + K − 1, — длина фрагмента (в программе K — это k): positions[j + k - 1] - positions[j] + 1.
s = 'CAABACAB'k = 3positions = [i for i in range(len(s)) if s[i] == 'A']print(positions) best = len(s) + 1for j in range(len(positions) - k + 1): best = min(best, positions[j + k - 1] - positions[j] + 1) print(best)Тройки соседних A: на позициях 1, 2, 4 — фрагмент AABA длины 4, и на позициях 2, 4, 6 — длины 5. Брать A не подряд нет смысла: та, что между ними, всё равно окажется внутри. Начальное значение len(s) + 1 больше любой длины — если оно не изменилось, подходящего фрагмента нет.
Ровно K: до соседей
А самый длинный фрагмент ровно с K буквами A? Насколько его можно растянуть?
До соседних A, не включая их: левее первой выбранной — до предыдущей A, правее последней — до следующей. Чтобы та же формула работала у краёв строки, добавим в список искусственные позиции −1 и len(s) — как будто там стоят A. Тогда длина — positions[j + k] - positions[j - 1] - 1.
s = 'BABAACB'k = 2positions = [i for i in range(len(s)) if s[i] == 'A']positions = [-1] + positions + [len(s)]best = 0for j in range(1, len(positions) - k): best = max(best, positions[j + k] - positions[j - 1] - 1) print(positions, best)Первые две A растягиваются от начала строки до позиции 3 — BABA, длина 4. Последние две — от позиции 2 до конца строки: BAACB, длина 5.
Это тот же ответ, что дало скользящее окно в подтеме 4. Позиции удобнее, когда K большое, а нужные буквы редкие: цикл идёт по списку, а не по всей строке.
Вхождения слова
Самый короткий фрагмент с двумя вхождениями слова ABA — как его найти, если вхождения могут перекрываться?
Так же, по списку позиций, только теперь это начала слова. Последнее слово кончается на m − 1 символов дальше своего начала, поэтому длина — starts[j + k - 1] - starts[j] + m. Начала ищем перебором, как в подтеме 3, — перекрытия не теряются.
s = 'ABACABABA'word = 'ABA'm = len(word)starts = [i for i in range(len(s) - m + 1) if s[i:i + m] == word]best = len(s) + 1for j in range(len(starts) - 1): best = min(best, starts[j + 1] - starts[j] + m) print(starts, best)Вхождения с позиций 4 и 6 перекрываются, вместе это ABABA — 5 символов, а не 6. Та же формула работает для пар вроде TT: m = 2.
Начало и конец
Фрагмент начинается и заканчивается одной и той же цифрой, а внутри только буквы. Где искать его концы?
Только среди соседних цифр строки: если между концами окажется ещё одна цифра, внутри будут уже не только буквы. Значит, перебираем пары соседних позиций цифр. s[i].isdigit() проверяет, что символ — цифра.
s = '5BA57OK7TEX2KA9'digits = [i for i in range(len(s)) if s[i].isdigit()]best = 0for j in range(len(digits) - 1): a, b = digits[j], digits[j + 1] if s[a] == s[b]: best = max(best, b - a + 1) print(digits, best)Подходят 5BA5 и 7OK7, обе длины 4. Пара 2…9 — разные цифры. Так решаются многие задачи с особыми концами: сначала выписать, где могут стоять концы, потом проверить пары — это гораздо меньше, чем перебор всех фрагментов.
Похоже устроено условие «фрагмент без цифр, в котором есть все шесть гласных»: цифры делят строку на блоки букв, и для максимума выгодно брать блок целиком. Проверка — set('AEIOUY') <= set(block): все гласные есть среди букв блока.
Итого
- Самый короткий с K
positions[j + k - 1] - positions[j] + 1 - Самый длинный ровно с K
positions[j + k] - positions[j - 1] - 1 - Искусственные границы−1 и len(s) в начале и в конце списка
- Слово длины mпоследнее начало − первое + m
- Особые концыконцы — среди позиций особых символов, перебор пар
Проверьте себя
Ответь сначала сам, потом открой ответ.
ОтветСкрыть ответ
ОтветСкрыть ответ
ОтветСкрыть ответ
ОтветСкрыть ответ
ОтветСкрыть ответ
Практика
Для проверки ответов нужен JavaScript. Условия, подсказки и решения доступны ниже.
Три A покороче
В строке CAABACAB буквы A стоят на позициях 1, 2, 4, 6. Найди минимальную длину фрагмента с тремя A.
Введите число.
Подсказка
Три подряд идущие позиции A: длина positions[j + 2] − positions[j] + 1.
Решение
4: три подряд идущие A на позициях 1, 2, 4 — фрагмент AABA; вариант 2, 4, 6 длиннее.
Решение программой
s = 'CAABACAB'k = 3positions = [i for i in range(len(s)) if s[i] == 'A']best = len(s) + 1for j in range(len(positions) - k + 1): length = positions[j + k - 1] - positions[j] + 1 best = min(best, length)print(best)Ответ: 4
Не менее двух A, короче всего
В строке ABCABBACB найди минимальную длину фрагмента, в котором не менее двух букв A.
Введите число.
Подсказка
Самый короткий фрагмент начинается на A и кончается на следующей A из списка позиций.
Решение
4: ABBA или ABCA — между соседними A по два символа.
Решение программой
s = 'ABCABBACB'left = count = 0best = len(s) + 1for right in range(len(s)): if s[right] == 'A': count += 1 while count >= 2: best = min(best, right - left + 1) if s[left] == 'A': count -= 1 left += 1print(best)Ответ: 4
50 букв Q покороче
Текстовый файл 24-4.txt содержит заглавные латинские буквы. Определите минимальное количество идущих подряд символов, среди которых буква Q встречается 50 раз.
Введите число.
Подсказка
K подряд идущих позиций Q.
Решение
7345.
Решение программой
s = open('24-4.txt').readline().strip() k = 50positions = [i for i in range(len(s)) if s[i] == 'Q']best = len(s) + 1for j in range(len(positions) - k + 1): length = positions[j + k - 1] - positions[j] + 1 best = min(best, length)print(best)Ответ: 7345
Ровно две A через позиции
В строке CAABACAB найди максимальную длину фрагмента, в котором ровно две буквы A.
Введите число.
Подсказка
Добавь границы −1 и len(s) и растяни фрагмент до соседних A.
Решение
5: список с границами [-1, 1, 2, 4, 6, 8], для пары A на 4 и 6 — от позиции 3 до 7, BACAB.
Решение программой
s = 'CAABACAB'k = 2positions = [i for i in range(len(s)) if s[i] == 'A']positions = [-1] + positions + [len(s)]best = 0for j in range(1, len(positions) - k): left = positions[j - 1] + 1 right = positions[j + k] - 1 best = max(best, right - left + 1)print(best)Ответ: 5
Два вхождения ABA
В ABACABAABA найди минимальную длину фрагмента с двумя вхождениями ABA.
Введите число.
Подсказка
Начала слова — позиции; длина positions[j + 1] − positions[j] + 3.
Решение
6: начала ABA — 0, 4, 7; для 4 и 7 длина 7 − 4 + 3.
Решение программой
s = 'ABACABAABA'word, k = 'ABA', 2m = len(word)positions = [i for i in range(len(s) - m + 1) if s[i:i + m] == word]best = len(s) + 1for j in range(len(positions) - k + 1): length = positions[j + k - 1] - positions[j] + m best = min(best, length)print(best)Ответ: 6
Конец на 0 и ровно 6 K
Текстовый файл 24-5.txt состоит из заглавных латинских букв и десятичных цифр. Определите минимальное количество идущих подряд символов, которые заканчиваются цифрой 0, содержат цифру 0 ровно один раз и содержат ровно 6 букв K.
Введите число.
Подсказка
Фрагмент кончается на 0, внутри нуля нет: после каждого 0 список позиций K начинается заново.
Решение
43: после каждой цифры 0 список позиций K начинается заново.
Решение программой
s = open('24-5.txt').readline().strip() k = 6positions = []best = len(s) + 1for i in range(len(s)): if s[i] == 'K': positions.append(i) elif s[i] == '0': if len(positions) >= k: best = min(best, i - positions[-k] + 1) positions = []print(best)Ответ: 43
Цифра, буквы, та же цифра
Для файла 24-5.txt найдите самую длинную последовательность символов, которая начинается и заканчивается одной и той же цифрой, кратной 3, содержит между ними только буквы (хотя бы одну) и поровну гласных и согласных букв. Гласные — A, E, I, O, U, Y. Если таких несколько, выберите последовательность с наибольшим номером первого символа. В ответе запишите номер первого символа; нумерация символов файла начинается с нуля.
Введите число.
Подсказка
Концы — соседние цифры файла; при равной длине бери больший номер начала.
Решение
210001: два фрагмента одинаковой наибольшей длины, выбран тот, что правее; фрагмент длиннее с цифрой 4 не подходит — 4 не кратна 3.
Решение программой
s = open('24-5.txt').readline().strip() vowels = 'AEIOUY'digits = [i for i in range(len(s)) if s[i].isdigit()]best, start = 0, -1for a, b in zip(digits, digits[1:]): if s[a] == s[b] and s[a] in '0369' and b - a > 1: inside = s[a + 1:b] v = sum(c in vowels for c in inside) if 2 * v == len(inside) and b - a + 1 >= best: best, start = b - a + 1, aprint(start)Ответ: 210001
Все шесть гласных без цифр
Для файла 24-5.txt определите максимальное количество идущих подряд символов, среди которых нет ни одной цифры и встречаются все шесть гласных A, E, I, O, U, Y.
Введите число.
Подсказка
Цифра обрывает фрагмент; множество встреченных гласных сбрасывается вместе с длиной.
Решение
44.
Решение программой
s = open('24-5.txt').readline().strip() vowels = 'AEIOUY'current, seen, best = 0, set(), 0for c in s: if c.isalpha(): current += 1 if c in vowels: seen.add(c) else: current, seen = 0, set() if len(seen) == len(vowels): best = max(best, current)print(best)Ответ: 44