Это является частью серии объяснений решения LeetCode ( index ). Если вам понравилось это решение или нашли его полезным, Пожалуйста, нравится Этот пост и/или upvote Мое решение по сообщению на форумах LeetCode Анкет
Проблема LeetCode #105 (Среда): построить двоичное дерево из предварительного заказа и обхода на заказ
Описание:
( прыгнуть в : Идея решения Код : JavaScript | Python | Java | C ++
Учитывают два целочисленных массива предварительный заказ
и inorder
где предварительный заказ
это предварительное прохождение бинарного дерева и inorder
это обход по заказу одного и того же дерева, построить и вернуть двоичное дерево Анкет
Примеры:
Вход: | предварительный заказ = [3,9,20,15,7], inorder = [9,3,15,20,7] |
Выход: | [3,9,20, NULL, NULL, 15,7] |
Визуальный: |
Вход: | предварительный заказ = [-1], inorder = [-1] |
Выход: | [-1] |
Ограничения:
1. длиной
inorder.length.length
-3000 [i], inorder [i]
предварительный заказ
иinorder
состоят из уникальных значений.- Каждое значение
inorder
Также появляется впредварительный заказ
Анкет предварительный заказ
гарантированно будет предварительным проходом дерева.inorder
гарантированно будет облицовка дерева.
Идея:
( Прыгните к : Описание задачи Код : JavaScript | Python | Java | C ++
Для этого решения мы можем воспользоваться порядок узлов в предварительный заказ и inorder проходы. Предварительный заказ – это [Узел, слева, справа] в то время как обход по заказу – это [Слева, Узел, справа] Анкет
Мы знаем, что корень Узел для дерева является первым элементом массива предварительного заказа ( P ). Мы также знаем, что каждый элемент слева от корневого элемента в массиве Inorder ( i ) находится на левой поддерею, и все справа от корень элемент в Я находится на правом поддерево.
Поскольку мы знаем длину левого и правого подтережав, обнаружив корень в Я , и так как мы знаем порядок левых и правых подтерей в P , мы можем использовать это, чтобы определить местоположение корень Узел в P для каждого из двух подтереев.
С этой информацией мы можем определить рекурсивный вспомогательная функция ( SplitTree ) это разделяет дерево на два, а затем рекурсивно сделает то же самое для каждого поддерева.
Чтобы сделать эту работу, нам просто нужно пройти влево и правое ограничения ( ilft, iright ) Определение субаррея текущего поддерева в Я , а также индекс ( pix ) из корень Узел поддерево в P .
На данный момент мы мог переходить вперед через Я Пока мы не узнаем местоположение ( imid ) из корень Узел каждый раз, но это подтолкнет это решение к Сложность времени из O (n^2) Анкет
Вместо этого мы можем сделать предварительное место Индексная карта ( m ) значений в Я , чтобы мы могли искать значение для имид в O (1) время в каждой рекурсии. Это снизит сложность времени до O (n) за счет Сложность пространства из O (n) Анкет
В примере на графике выше, где P = [8,2,7,1,9,3,6] и I = [7,2,1,8,3,9,6] , корень было бы 8 , Итак, мы знаем, что Imid (его местоположение в Я ) это 3 , и так как мы все еще используем полный массив, Ileft и iright.length-1 , или 6 Анкет Это означает, что левый поддерек – это Imid – Элементы долго ( [7,2,1] слева от 8 in Я ) и правильная поддерево Iright – Элементы длинные ( [3,9,6] справа от 8 I ).
Мы можем применить эти измерения из Я выяснить диапазоны этих подтереев в P , также. Левый поддерек начнется сразу после корень в P ( pix + 1 ), и правая подтерек запустится, как только левое подтерее завершится ( pix + 1 + (imid – ilft) .
При каждой рекурсии, если Imid Тогда в левом поддерере нет узлов, поэтому мы не должны вызывать рекурсию для этой стороны. То же самое относится и к правой стороне, если имид .
- Сложность времени: O (n) куда N является длиной P и I
- Сложность пространства: O (n) за M
Код JavaScript:
( Прыгните к : Описание задачи Идея решения
var buildTree = function(P, I) { let M = new Map() for (let i = 0; i < I.length; i++) M.set(I[i], i) return splitTree(P, M, 0, 0, I.length-1) }; var splitTree = function(P, M, pix, ileft, iright) { let rval = P[pix], root = new TreeNode(rval), imid = M.get(rval) if (imid > ileft) root.left = splitTree(P, M, pix+1, ileft, imid-1) if (imid < iright) root.right = splitTree(P, M, pix+imid-ileft+1, imid+1, iright) return root }
Код Python:
( Прыгните к : Описание задачи Идея решения
class Solution: def buildTree(self, P: List[int], I: List[int]) -> TreeNode: M = {I[i]: i for i in range(len(I))} return self.splitTree(P, M, 0, 0, len(P)-1) def splitTree(self, P: List[int], M: dict, pix: int, ileft: int, iright: int) -> TreeNode: rval = P[pix] root, imid = TreeNode(rval), M[rval] if imid > ileft: root.left = self.splitTree(P, M, pix+1, ileft, imid-1) if imid < iright: root.right = self.splitTree(P, M, pix+imid-ileft+1, imid+1, iright) return root
Код Java:
( Прыгните к : Описание задачи Идея решения
class Solution { public TreeNode buildTree(int[] P, int[] I) { MapM = new HashMap<>(); for (int i = 0; i < I.length; i++) M.put(I[i], i); return splitTree(P, M, 0, 0, I.length-1); } private TreeNode splitTree(int[] P, Map M, int pix, int ileft, int iright) { int rval = P[pix], imid = M.get(rval); TreeNode root = new TreeNode(rval); if (imid > ileft) root.left = splitTree(P, M, pix+1, ileft, imid-1); if (imid < iright) root.right = splitTree(P, M, pix+imid-ileft+1, imid+1, iright); return root; } }
C ++ Код:
( Прыгните к : Описание задачи Идея решения
class Solution { public: TreeNode* buildTree(vector& P, vector & I) { unordered_map M; for (int i = 0; i < I.size(); i++) M[I[i]] = i; return splitTree(P, M, 0, 0, I.size()-1); } private: TreeNode* splitTree(vector & P, unordered_map & M, int pix, int ileft, int iright) { int rval = P[pix], imid = M[rval]; TreeNode* root = new TreeNode(rval); if (imid > ileft) root->left = splitTree(P, M, pix+1, ileft, imid-1); if (imid < iright) root->right = splitTree(P, M, pix+imid-ileft+1, imid+1, iright); return root; } };
Оригинал: “https://dev.to/seanpgallivan/solution-construct-binary-tree-from-preorder-and-inorder-traversal-32c5”