Как реализовать функцию сжатия строки с повторяющимися символами в Python?
Что проверяют
Напишете ли вы корректное решение и вспомните ли про случай, когда сжатие невыгодно.
Как отвечать
Задача это кодирование длин серий: подряд идущие одинаковые символы заменяются на символ и количество.
Уточните условие до кода: писать ли единицу для одиночных символов и что возвращать, если результат длиннее исходной строки. Обычно требуют вернуть исходную.
from itertools import groupby
def compress(s: str) -> str:
if not s:
return s
parts = []
for ch, group in groupby(s):
n = sum(1 for _ in group)
parts.append(ch if n == 1 else f"{ch}{n}")
result = "".join(parts)
return result if len(result) < len(s) else sВариант без библиотеки, если просят вручную:
def compress(s: str) -> str:
if not s:
return s
parts, prev, count = [], s[0], 1
for ch in s[1:]:
if ch == prev:
count += 1
else:
parts.append(prev if count == 1 else f"{prev}{count}")
prev, count = ch, 1
parts.append(prev if count == 1 else f"{prev}{count}")
result = "".join(parts)
return result if len(result) < len(s) else sЧто стоит проговорить:
- сложность O(n) по времени и O(n) по памяти;
- сборка через список и
join, а не конкатенация в цикле. Строки неизменяемы, поэтому склейка в цикле создаёт новую строку на каждом шаге и даёт квадратичное поведение; - краевые случаи: пустая строка, строка из одного символа, строка без повторов вовсе;
groupbyгруппирует только подряд идущие элементы, что здесь ровно то, что нужно. Для группировки по всей строке её пришлось бы сначала отсортировать.
Если спросят про обратную операцию, стоит заметить, что при таком формате она неоднозначна для строк с цифрами, и в реальном протоколе нужен разделитель или экранирование.
Где спотыкаются
Забывают обработать последнюю серию после цикла.
Склеивают строку конкатенацией в цикле.
Не возвращают исходную строку, когда сжатие не выгодно.
Не проверяют пустой ввод.