SprintCode.pro

Подготовка к алгоритмическим задачам

Super

Структуры данных на собеседовании: что спрашивают и как отвечать

12 мин чтения
собеседование
структуры данных
подготовка

Коротко

Главный вопрос интервьюера — не «что такое хеш-таблица», а «какую структуру вы возьмёте и почему». Ниже таблица, которую стоит держать в голове.

СтруктураПоискВставкаУдалениеПорядок
МассивO(n)O(n)O(n)сохраняется
Динамический массивO(n)O(1) в конецO(n)сохраняется
Связный списокO(n)O(1) по ссылкеO(1) по ссылкесохраняется
Хеш-таблицаO(1)O(1)O(1)нет
МножествоO(1)O(1)O(1)нет
Сбалансированное деревоO(log n)O(log n)O(log n)отсортированный
КучаO(n)O(log n)O(log n)только минимум
Стек / очередьO(1)O(1)LIFO / FIFO

Как выбирать структуру

Схема из четырёх вопросов, которую полезно проговаривать вслух на собеседовании.

1. Нужен ли быстрый поиск по ключу? → хеш-таблица.

2. Нужен ли порядок? → отсортированный массив или сбалансированное дерево.

3. Нужны ли только минимум или максимум? → куча.

4. Важен ли порядок обработки? → стек для LIFO, очередь для FIFO.

Если ни один пункт не подходит, обычно достаточно массива.

Массив против связного списка

Классический вопрос, который задают почти всегда.

Массив: доступ по индексу за O(1), данные лежат непрерывно, отлично работает с кешем процессора. Вставка в середину O(n) из-за сдвига.

Связный список: вставка и удаление за O(1), если ссылка на узел уже есть. Доступа по индексу нет — только последовательный обход.

Сильный ответ включает практическую поправку: на реальных данных массив обычно быстрее даже там, где теория обещает обратное. Причина в локальности памяти: элементы массива подгружаются в кеш блоками, а список разбросан по куче, и каждый переход по указателю может стоить обращения к оперативной памяти.

Связный список выигрывает в узкой нише: частые вставки и удаления в середине при наличии ссылки на узел. Именно поэтому он лежит в основе LRU-кэша.

Хеш-таблица

Вторая по частоте тема после массивов.

Что должен содержать ответ

Массив корзин. Ключ прогоняется через хеш-функцию, остаток от деления на размер даёт номер корзины. При совпадении корзин — коллизия.

Два способа разрешения:

  • цепочки — в корзине связный список или дерево;
  • открытая адресация — ищем следующую свободную ячейку.

При заполнении выше порога (обычно 0.75) таблица увеличивается вдвое, и все элементы перераспределяются.

Почему O(1) «в среднем»

Потому что в худшем случае все ключи попадут в одну корзину, и поиск выродится в O(n). Современные реализации это смягчают: в Java при восьми элементах в корзине список превращается в красно-чёрное дерево, что даёт O(log n) вместо O(n).

Упоминание худшего случая — признак понимания, а не заучивания.

Что может быть ключом

Только неизменяемые объекты с корректными hashCode и equals. Если объект изменится после вставки, его хеш изменится, и найти его станет невозможно.

Отсюда классический вопрос: «что будет, если переопределить equals без hashCode». Ответ: объект не найдётся в хеш-таблице, потому что поиск пойдёт не в ту корзину.

Пройди собеседование в топ-компанию
Платформа для подготовки

Решай алгоритмические задачи как профи

✓ Популярные алгоритмы✓ Разбор решений✓ AI помощь
Начать сейчас
Программист за работой

Стек и очередь

Простые структуры, но задачи на них дают часто.

Стек нужен, когда обработка идёт в обратном порядке или есть вложенность: скобки, обход в глубину, отмена действий, вычисление выражений.

Очередь — когда порядок поступления важен: обход в ширину, планировщики, буферы.

Практическая деталь, которую ценят: в Python для очереди нужен collections.deque, а не список. list.pop(0) работает за O(n), и цикл превращается в скрытый квадрат.

Деревья

Двоичное дерево поиска

Левое поддерево меньше, правое больше. Даёт O(log n) на поиск — но только если дерево сбалансировано.

Обязательное дополнение к ответу: на отсортированных данных обычное дерево поиска вырождается в связный список и деградирует до O(n). Отсюда самобалансирующиеся деревья — АВЛ и красно-чёрное.

Что где применяется

TreeMap в Java и std::map в C++ — красно-чёрные деревья. Индексы баз данных — B+ деревья, у которых узел размером с дисковый блок содержит сотни ключей и высота падает до 3–4 уровней.

Куча

Отвечает на один вопрос — «какой элемент минимальный» — и делает это за O(1).

Ключевые факты для ответа:

  • это полное двоичное дерево, хранящееся в массиве без указателей;
  • дети узла i лежат на позициях 2i+1 и 2i+2;
  • вставка и извлечение — O(log n);
  • построение из готового массива — O(n), а не O(n log n);
  • найти произвольный элемент нельзя быстрее O(n).

Последний пункт важен: куча не заменяет дерево поиска, порядок между «братьями» в ней не определён.

Типичные вопросы-ловушки

«Какая сложность у поиска в хеш-таблице?» Ответ «O(1)» неполный. Правильно: O(1) в среднем, O(n) в худшем случае при плохой хеш-функции.

«Массив или список для стека?» Массив. Операции идут с одного конца, а локальность памяти даёт выигрыш.

«Как найти k-й наибольший элемент?» Три варианта с разной сложностью: сортировка O(n log n), куча размера k — O(n log k), quickselect — O(n) в среднем. Хороший ответ перечисляет все три и объясняет, когда что выгоднее.

«Чем множество отличается от словаря?» Множество хранит только ключи, словарь — пары. Внутри устроены одинаково.

«Где применяется стек в реальном коде?» Стек вызовов функций, обход DOM, отмена действий, парсеры.

Как отвечать

Не заучивайте определения. Спросят «когда применять», а не «что это».

Всегда называйте сложность — по времени и по памяти.

Упоминайте худший случай. Это отличает понимание от зубрёжки.

Приводите примеры из практики. «Мы взяли множество вместо списка, и проверка дубликатов ускорилась с секунд до миллисекунд» весит больше теории.

Обсуждайте компромиссы. Почти всегда речь идёт о размене памяти на скорость, и явное упоминание этого ценится.

Что запомнить

  • Ключевой вопрос — не «что это», а «какую структуру выбрать и почему».
  • Хеш-таблица даёт O(1) в среднем и O(n) в худшем случае — говорите про оба.
  • Массив на практике обгоняет связный список из-за локальности памяти.
  • Дерево поиска без балансировки вырождается в список на отсортированных данных.
  • Куча отвечает только за минимум; произвольный поиск в ней O(n).
  • В Python для очереди используйте deque, а не список.

Задачи по теме