Условие
Определить длину наибольшей последовательности одинаковых подряд символов в строке.
str = 'fffggggrrrrrrrrrtttfffff'
ответ: 9 # 'rrrrrrrrr'
Решение
Подход 1 — itertools.groupby (самый идиоматичный)
from itertools import groupby
def longest_run(s: str) -> int:
if not s:
return 0
return max(sum(1 for _ in g) for _, g in groupby(s))
print(longest_run('fffggggrrrrrrrrrtttfffff')) # 9groupby группирует подряд идущие одинаковые элементы; для каждой группы считаем длину.
Подход 2 — однопроходный
def longest_run(s: str) -> int:
if not s:
return 0
best = cur = 1
for i in range(1, len(s)):
if s[i] == s[i - 1]:
cur += 1
best = max(best, cur)
else:
cur = 1
return bestO(n) по времени, O(1) по памяти.
Подход 3 — regex
import re
def longest_run(s: str) -> int:
if not s:
return 0
return max((len(m.group()) for m in re.finditer(r'(.)\1*', s)), default=0)(.)\1* — символ и его повторы. На очень длинных строках регексп медленнее однопроходного.
Тесты
assert longest_run('fffggggrrrrrrrrrtttfffff') == 9
assert longest_run('') == 0
assert longest_run('a') == 1
assert longest_run('abcde') == 1
assert longest_run('aabbbccccdddd') == 4 # 'cccc' и 'dddd' оба по 4Подводные камни
- Пустая строка. Не забыть отдельный случай — иначе
maxна пустом итерабле падает. groupbyбез сортировки. В отличие от SQLGROUP BY,itertools.groupbyгруппирует подряд идущие, без сортировки. Это и нужно — порядок важен.- Юникод и комбинируемые символы. В строке
'á'(где á —'a' + combining acute) формально две кодовые точки, но визуально один символ. Если задача про graphemes — нуженunicodedataилиregexс\X. - Регистр.
'Aaaa'— это 4 одинаковых или 1+3? Уточнить у бизнеса; обычно — case-sensitive. - Сравнение позиций. В цикле
range(1, len(s))важно начинать с 1, иначеs[i-1]упадёт на индексе −1.
Эталонный ответ
from itertools import groupby
def longest_run(s):
return max((sum(1 for _ in g) for _, g in groupby(s)), default=0)groupby группирует подряд одинаковые → длина каждой группы → max. Алгоритмически — O(n).