Алгоритмы с нуля
Heap: тест с выбором ответа
Шесть вопросов, проходящих через весь юнит. Ни один не на заучивание определений — каждый это проектное решение: какой heap, какая сложность, какой инвариант. Выберите ответ, который защитили бы на собеседовании, затем прочитайте, почему каждый отвлекающий вариант ошибочен.
Убедитесь, что можете связать инвариант heap, аргумент O(n) для build-heap, контракт priority queue и приём «heap размера k», на котором строятся и top-k, и k-way merge — синтез, к которому вели пять уроков.
Интервьюер даёт массив [10, 5, 20, 15, 30] и спрашивает: «это корректный min-heap?» Каков верный ответ и почему?
Построение heap из массива n элементов через n вызовов push даёт O(n log n), но стандартный build-heap (heapify) — O(n). Откуда ускорение?
Коллега говорит: «priority queue — это просто heap». Почему это неточно и когда различие реально важно?
Нужно держать k наибольших элементов из потока n чисел (k ≪ n). Какой heap и почему именно он, а не другой?
В k-way merge из k отсортированных списков с n элементами всего каждая запись в heap хранит (value, listIndex, position), а не только значение. Зачем эта учётная информация?
При pop из min-heap последний элемент массива переносится в корень, массив уменьшается на один, затем делается sift-down. Почему поднимают ПОСЛЕДНИЙ элемент, а не продвигают меньшего ребёнка в образовавшуюся дыру?
Сквозная линия юнита — одна структура, выполняющая много ролей. Свойство heap плюс форма полного дерева дают peek за O(1) и push/pop за O(log n) через sift-up и sift-down; build-heap использует распределение высот и достигает O(n). Оберните это в контракт priority queue — и та же машина становится планировщиком, фильтром top-k (min-heap размера k, вытесняем корень) и k-way merge (по одному кандидату от списка, продвигаем по listIndex). Каждый вопрос здесь был по сути про «какой инвариант или какой heap» — ровно то решение, что вы принимаете на собеседовании или в реальной системе.