К содержанию

Подтема 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)
[1, 2, 4, 6] 4

Тройки соседних 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)
[-1, 1, 3, 4, 7] 5

Первые две A растягиваются от начала строки до позиции 3 — BABA, длина 4. Последние две — от позиции 2 до конца строки: BAACB, длина 5.

Пунктирные клетки −1 и 7 — искусственные границы: окно BABA упирается в начало строки, окно BAACB — в конец, а длина обоих считается одной формулой.

Это тот же ответ, что дало скользящее окно в подтеме 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)
[0, 4, 6] 5

Вхождения с позиций 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)
[0, 3, 4, 7, 11, 14] 4

Подходят 5BA5 и 7OK7, обе длины 4. Пара 2…9 — разные цифры. Так решаются многие задачи с особыми концами: сначала выписать, где могут стоять концы, потом проверить пары — это гораздо меньше, чем перебор всех фрагментов.

Похоже устроено условие «фрагмент без цифр, в котором есть все шесть гласных»: цифры делят строку на блоки букв, и для максимума выгодно брать блок целиком. Проверка — set('AEIOUY') <= set(block): все гласные есть среди букв блока.

Итого

  • Самый короткий с Kpositions[j + k - 1] - positions[j] + 1
  • Самый длинный ровно с Kpositions[j + k] - positions[j - 1] - 1
  • Искусственные границы−1 и len(s) в начале и в конце списка
  • Слово длины mпоследнее начало − первое + m
  • Особые концыконцы — среди позиций особых символов, перебор пар

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

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

Вопрос 1
Буквы A стоят на позициях 3, 8, 9 и 15. Какова длина самого короткого фрагмента с тремя A?
ОтветСкрыть ответ
Ответ
7: от 3 до 9 включительно. Вторая тройка, с 8 по 15, длиннее — 8.
Вопрос 2
Зачем в список позиций добавляют −1 и len(s)?
ОтветСкрыть ответ
Ответ
Чтобы фрагмент, упирающийся в начало или конец строки, считался той же формулой, что и в середине.
Вопрос 3
В строке длины 20 буквы B стоят на позициях 2, 5, 11 и 14. Какова длина самого длинного фрагмента ровно с двумя B?
ОтветСкрыть ответ
Ответ
14: список [−1, 2, 5, 11, 14, 20], лучшая пара — B на 11 и 14, фрагмент от 6 до 19.
Вопрос 4
Какова длина самого короткого фрагмента с двумя вхождениями TT в строке ATTTA?
ОтветСкрыть ответ
Ответ
3: TTT — пары с позиций 1 и 2 перекрываются, 2 − 1 + 2 = 3.
Вопрос 5
Фрагмент начинается и кончается цифрой, внутри только буквы. Почему его концы — соседние цифры строки?
ОтветСкрыть ответ
Ответ
Если между концами есть ещё цифра, она окажется внутри фрагмента, а там разрешены только буквы.

Практика

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

Три A покороче

В строке CAABACAB буквы A стоят на позициях 1, 2, 4, 6. Найди минимальную длину фрагмента с тремя A.

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

Не менее двух A, короче всего

В строке ABCABBACB найди минимальную длину фрагмента, в котором не менее двух букв A.

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

50 букв Q покороче

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

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

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

Ровно две A через позиции

В строке CAABACAB найди максимальную длину фрагмента, в котором ровно две буквы A.

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

Два вхождения ABA

В ABACABAABA найди минимальную длину фрагмента с двумя вхождениями ABA.

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

Конец на 0 и ровно 6 K

Текстовый файл 24-5.txt состоит из заглавных латинских букв и десятичных цифр. Определите минимальное количество идущих подряд символов, которые заканчиваются цифрой 0, содержат цифру 0 ровно один раз и содержат ровно 6 букв K.

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

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

Цифра, буквы, та же цифра

Для файла 24-5.txt найдите самую длинную последовательность символов, которая начинается и заканчивается одной и той же цифрой, кратной 3, содержит между ними только буквы (хотя бы одну) и поровну гласных и согласных букв. Гласные — A, E, I, O, U, Y. Если таких несколько, выберите последовательность с наибольшим номером первого символа. В ответе запишите номер первого символа; нумерация символов файла начинается с нуля.

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

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

Все шесть гласных без цифр

Для файла 24-5.txt определите максимальное количество идущих подряд символов, среди которых нет ни одной цифры и встречаются все шесть гласных A, E, I, O, U, Y.

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

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