Как отсортировать символы в строке в Python, минимизируя использование памяти?

«Как отсортировать символы в строке в Python, минимизируя использование памяти?» — вопрос из категории Алгоритмы и структуры данных, который задают на 26% собеседований Data Scientist / ML Инженер. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Для сортировки строки с минимальным использованием памяти в Python оптимальным решением является использование встроенной функции sorted(), которая возвращает новый отсортированный список символов, с последующим объединением этого списка в строку методом str.join(). Это стандартный идиоматичный подход.

Базовое решение:

input_string = "bca"
sorted_string = ''.join(sorted(input_string))
print(sorted_string)  # Вывод: "abc"

Почему это эффективно по памяти?

  • sorted(s) создаёт один новый список размера O(n), где n — длина строки.
  • ''.join(...) создаёт одну итоговую строку, также размера O(n).
  • Общее потребление памяти — O(n), что является теоретическим минимумом для задачи, требующей создания новой отсортированной строки (так как строки в Python неизменяемы).

Альтернативы и их анализ:

  1. Сортировка на месте (невозможна): Поскольку строки в Python неизменяемы (immutable), отсортировать исходную строку без создания новых объектов нельзя.

  2. Использование collections.Counter: Этот метод может быть более эффективен по памяти, только если в строке очень мало уникальных символов (например, строка из миллионов повторений 'a', 'b', 'c').

    from collections import Counter
    
    def sort_with_counter(s: str) -> str:
        counter = Counter(s)
        # Сортируем ключи (уникальные символы) и повторяем каждый нужное количество раз
        return ''.join(char * count for char, count in sorted(counter.items()))
    
    print(sort_with_counter("bbbaaac"))  # Вывод: "aaabbbc"
    • Плюс: Потребление памяти O(k), где k — количество уникальных символов (обычно k << n).
    • Минус: Добавляет overhead на создание и итерацию по словарю. Для строк со многими уникальными символами (например, случайных) sorted() будет быстрее и проще.

Вывод: Для большинства практических случаев ''.join(sorted(s)) — это лучшее решение: оно лаконичное, быстрое и понятное. Я прибегаю к оптимизации через Counter только при работе с экстремально большими строками, имеющими высокую степень повторяемости символов, и когда профилирование подтверждает, что память является узким местом.