Однажды я дал интервью «одной известной компании», и интервьюер попросил меня найти медианное значение BST.
int median(treeNode* root)
{
}
Я начал внедрять первое из предложенных мной решений методом перебора. Я заполняю все данные в std::vector<int>
с обходом по порядку (чтобы все отсортировано в векторе) и получил средний элемент. Итак, мой алгоритм - O (N) для вставки каждого элемента в вектор и запроса среднего элемента с O (1), + O (N) памяти. Есть ли более эффективный способ (с точки зрения памяти или сложности) сделать то же самое?
Заранее спасибо.
3 ответа
Это можно сделать во времени O(n)
и пространстве O(logN)
, выполнив обход по порядку и остановившись, когда вы достигнете n/2
-го узла, просто неся счетчик, который показывает, сколько узлов имеет уже пройдены - нет необходимости заполнять какой-либо вектор.
Если вы можете изменить свое дерево на ранговое дерево (каждый узел также имеет информацию о количестве узлов в поддереве, корнем которого он является), вы можете легко решить его за время O (logN), просто перемещаясь в направлении n. / 2 элемента.
Двоичное дерево предлагает отсортированное представление для ваших данных, но для того, чтобы воспользоваться им, вам нужно знать, сколько элементов находится в каждом поддереве. Итак, без этих знаний ваш алгоритм будет достаточно быстрым.
Если вам известен размер каждого поддерева, вы выбираете каждый раз для посещения левого или правого поддерева, и это дает алгоритм O(log n)
, если двоичное дерево сбалансировано.
Поскольку вы знаете, что медиана - это средний элемент отсортированного списка элементов, вы можете просто взять средний элемент обхода по порядку и остановиться на нем, не сохраняя значения в векторе. Вам может потребоваться два обхода, если вы не знаете количество узлов, но это заставит решение использовать меньше памяти (O(h)
, где h
- высота вашего дерева; h = O(log n)
для сбалансированные деревья поиска).
Если вы можете увеличить дерево, вы можете использовать решение, которое я дал здесь, чтобы получить алгоритм O(log n)
.
Похожие вопросы
Связанные вопросы
Новые вопросы
c++
C ++ - это язык программирования общего назначения. Первоначально он был разработан как расширение C и имеет аналогичный синтаксис, но теперь это совершенно другой язык. Используйте этот тег для вопросов о коде (который должен быть) скомпилирован с помощью компилятора C ++. Используйте тег для конкретной версии для вопросов, связанных с конкретной версией стандарта [C ++ 11], [C ++ 14], [C ++ 17], [C ++ 20] или [C ++ 23] и т. Д. .