46. Сжатие повторяющихся символов в строке
Условие задачи:
Написать функцию curtail_str(letters: str) -> str, которая сжимает строку по сериям подряд идущих одинаковых символов.
Правила:
- если символ встречается подряд один раз, он остается без изменений
- если символ повторяется подряд несколько раз, вместо этой группы нужно записать символ и количество повторений
- обрабатываются только подряд идущие одинаковые символы
Примеры:
"" -> ""
"ABC" -> "ABC"
"AAA" -> "A3"
"AAABBXYZDDDDA" -> "A3B2XYZD4A"
"ABCABCABCCCCC" -> "ABCABCABC5"
Код задачи:
def curtail_str(letters: str) -> str:
...
assert curtail_str("") == ""
assert curtail_str("ABC") == "ABC"
assert curtail_str("AAA") == "A3"
assert curtail_str("AAABBXYZDDDDA") == "A3B2XYZD4A"
assert curtail_str("ABCABCABCCCCC") == "ABCABCABC5"
print("done")
Дополнительно:
- Почему в result выбран тип данных str?
- Оцени свой алгоритм с точки зрения On
Спойлеры к решению
Подсказки
- Нужно идти по строке слева направо.
- Нужно хранить текущий символ и количество его подряд идущих повторений.
- Если следующий символ такой же — увеличиваем счётчик.
- Если следующий символ другой — записываем предыдущую группу в результат.
- Если символ встретился один раз, записываем только символ.
- Если символ повторился несколько раз, записываем символ и количество.
- Для результата лучше использовать список, а в конце собрать строку через
"".join(...).
Решение
def curtail_str(letters: str) -> str:
if not letters:
return ""
result = []
current_char = letters[0]
count = 1
for char in letters[1:]:
if char == current_char:
count += 1
else:
if count == 1:
result.append(current_char)
else:
result.append(f"{current_char}{count}")
current_char = char
count = 1
if count == 1:
result.append(current_char)
else:
result.append(f"{current_char}{count}")
return "".join(result)
Проверка:
assert curtail_str("") == ""
assert curtail_str("ABC") == "ABC"
assert curtail_str("AAA") == "A3"
assert curtail_str("AAABBXYZDDDDA") == "A3B2XYZD4A"
assert curtail_str("ABCABCABCCCCC") == "ABCABCABC5"
print("done")
Результат:
done
Как работает алгоритм:
"AAABBXYZDDDDA"
Строка разбивается на подряд идущие группы:
AAA -> A3
BB -> B2
X -> X
Y -> Y
Z -> Z
DDDD -> D4
A -> A
Итог:
A3B2XYZD4A
Почему result лучше делать списком, а не строкой:
result = []
Функция должна вернуть строку, но собирать результат через список эффективнее. Если делать так:
result += piece
то при каждой конкатенации может создаваться новая строка, потому что строки в Python неизменяемые. На больших строках это может привести к лишним копированиям.
Поэтому лучше добавлять части в список:
result.append(piece)
а в конце один раз собрать строку:
return "".join(result)
Оценка сложности:
Время: O(n)
Память: O(n)
n — длина входной строки. Алгоритм проходит по строке один раз, поэтому время работы линейное. Дополнительная память нужна для списка частей результата.