어떤 이진트리의 전위순회, 중위순회한 순서가 나열된 두 배열이 주어진다. 이것으로 원래 트리를 만들어라. (단 모든 값은 유니크한 수를 갖는다.)
Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]
3
9 20
7 6 15 17
[3, 9,7,6, 20,15,17] preorder
^ ----- --------
left right
l p r
[7,9,6, 3, 15,20,17] inorder
^
^^^^^ ^^^^^^^^
left right
recursive with left side : (l ~ p-1)
recursive with right side : (p+1 ~ r)
the root idx of preorder's ->
- left side: l + 1
- right side: l + (p - l + 1)
기본적인 재귀 풀이
class Solution {
public:
TreeNode *build_tree(vector<int> pre, vector<int> in, int left, int right, int root_idx) {
// left, right -> index of in
// root_idx -> index of pre
if (left > right) /* base case */
return NULL;
int pivot = left;
/* search where is the index of root value in the inorder[] */
for (pivot = left; pivot <= right; pivot++) // O(n)
if (in[pivot] == pre[root_idx])
break;
TreeNode *node = new TreeNode;
node->val = pre[root_idx];
node->left = build_tree(pre, in, left, pivot - 1, root_idx + 1);
node->right = build_tree(pre, in, pivot + 1, right, root_idx + (pivot - left + 1));
return node;
}
TreeNode *buildTree(vector<int>& preorder, vector<int>& inorder) {
return build_tree(preorder, inorder, 0, inorder.size() - 1, 0);
}
};
preorder[root_idx] 의 값이 inorder[]에 어디에 위치하는지 찾는 로직이, 위의 방법에서는 O(n) 으로 리니어 탐색이었다면, 이를 해시테이블을 활용해 O(1)에 찾을 수 있다. 따라서 총 시간복잡도는 O(n)이 된다.
class Solution {
unordered_map<int, int> in_idx;
public:
TreeNode *build_tree(vector<int> pre, vector<int> in, int left, int right, int root_idx) {
// left, right -> index of in
// root_idx -> index of pre
if (left > right) /* base case */
return NULL;
int pivot = in_idx[pre[root_idx]]; // O(1)
TreeNode *node = new TreeNode;
node->val = pre[root_idx];
node->left = build_tree(pre, in, left, pivot - 1, root_idx + 1);
node->right = build_tree(pre, in, pivot + 1, right, root_idx + (pivot - left + 1));
return node;
}
TreeNode *buildTree(vector<int>& preorder, vector<int>& inorder) {
for (int i = 0; i < inorder.size(); i++)
in_idx[inorder[i]] = i;
return build_tree(preorder, inorder, 0, inorder.size() - 1, 0);
}
};