Algorithms & Data Structures | Tree Traversal
94. Binary Tree Inorder Traversal
Recursive
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> ret;
function<void(TreeNode*)> f = [&](TreeNode* node) {
if (node == NULL) { return; }
f(node->left);
ret.push_back(node->val);
f(node->right);
};
f(root);
return ret;
}
};
Iterative
class Solution {
public:
vector<int> inorderTraversal(TreeNode* root) {
vector<int> ret;
// the first node popped from stack will always be the one
// - with no left children
// - with all its left children visited
vector<TreeNode*> stack;
function<void(TreeNode*)> push = [&](TreeNode* node) {
TreeNode* curr = node;
while (curr != NULL) {
stack.push_back(curr);
curr = curr->left;
}
};
push(root);
while (stack.size()) {
TreeNode* curr = stack[stack.size() - 1];
stack.pop_back();
ret.push_back(curr->val);
push(curr->right);
}
return ret;
}
};
144. Binary Tree Preorder Traversal
Recursive
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> ret;
function<void(TreeNode*)> f = [&](TreeNode* node) {
if (node == NULL) { return; }
ret.push_back(node->val);
f(node->left);
f(node->right);
};
f(root);
return ret;
}
};
Iterative
class Solution {
public:
vector<int> preorderTraversal(TreeNode* root) {
vector<int> ret;
vector<TreeNode*> stack = {root};
while (stack.size() > 0) {
TreeNode* curr = stack[stack.size() - 1];
stack.pop_back();
if (curr == NULL) { continue; }
ret.push_back(curr->val);
stack.push_back(curr->right);
stack.push_back(curr->left);
}
return ret;
}
};
145. Binary Tree Postorder Traversal
Recursive
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<int> ret;
function<void(TreeNode*)> f = [&](TreeNode* node) {
if (node == NULL) { return; }
f(node->left);
f(node->right);
ret.push_back(node->val);
};
f(root);
return ret;
}
};
Iterative
class Solution {
public:
vector<int> postorderTraversal(TreeNode* root) {
vector<TreeNode*> arr;
vector<TreeNode*> stack;
function<void(TreeNode*)> push_left = [&](TreeNode* node) {
TreeNode* curr = node;
while (curr != NULL) {
stack.push_back(curr);
curr = curr->left;
}
};
if (root != NULL) { push_left(root); }
while (stack.size() > 0) {
// the first node popped from stack will always be the one
// - with no left children
// - with all its left children visited
TreeNode* curr = stack[stack.size() - 1];
stack.pop_back();
// if `curr->right` exists, in postorder traversal, the last output should be `curr->right`
// we can use this property to check if the right children have been visited
if (curr->right == NULL ||
(arr.size() > 0 && arr[arr.size() - 1] == curr->right)) {
arr.push_back(curr);
} else {
stack.push_back(curr);
push_left(curr->right);
}
}
vector<int> ret;
for (TreeNode* node : arr) { ret.push_back(node->val); }
return ret;
}
};
105. Construct Binary Tree from Preorder and Inorder Traversal
Recursive
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
unordered_map<int, int> mi;
for (int i = 0; i < inorder.size(); i += 1) {
mi.insert(make_pair(inorder[i], i));
}
function<TreeNode*(int, int, int, int)> f = [&](int ii, int ij, int pi,
int pj) {
assert(ij - ii == pj - pi);
if (ii > ij) { return (TreeNode*)NULL; }
TreeNode* node = new TreeNode(preorder[pi]);
int pri = mi.find(node->val)->second;
int lchildren_len = pri - ii;
node->left =
f(ii, ii + lchildren_len - 1, pi + 1, pi + lchildren_len);
node->right =
f(ii + lchildren_len + 1, ij, pi + lchildren_len + 1, pj);
return node;
};
return f(0, inorder.size() - 1, 0, preorder.size() - 1);
}
};
106. Construct Binary Tree from Inorder and Postorder Traversal
Recursive
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
unordered_map<int, int> mi;
for (int i = 0; i < inorder.size(); i += 1) {
mi.insert(make_pair(inorder[i], i));
}
function<TreeNode*(int, int, int, int)> f = [&](int ii, int ij, int pi,
int pj) {
assert(ij - ii == pj - pi);
if (ii > ij) { return (TreeNode*)NULL; }
TreeNode* node = new TreeNode(postorder[pj]);
int pri = mi.find(node->val)->second;
int lchildren_len = pri - ii;
node->left =
f(ii, ii + lchildren_len - 1, pi, pi + lchildren_len - 1);
node->right =
f(ii + lchildren_len + 1, ij, pi + lchildren_len, pj - 1);
return node;
};
return f(0, inorder.size() - 1, 0, postorder.size() - 1);
}
};
Iterative
class Solution {
public:
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
assert(inorder.size() == postorder.size());
if (inorder.size() == 0) { return (TreeNode*)NULL; }
unordered_map<int, int> mappings;
for (int i = 0; i < inorder.size(); i += 1) {
mappings[inorder[i]] = i;
}
TreeNode* root = new TreeNode(postorder[postorder.size() - 1]);
vector<TreeNode*> stack = {root};
for (int i = postorder.size() - 2; i >= 0; i -= 1) {
TreeNode* node = new TreeNode(postorder[i]);
assert(stack.size() > 0);
TreeNode* parent = stack.back();
while (stack.size() > 0 &&
mappings[node->val] < mappings[stack.back()->val]) {
parent = stack.back();
stack.pop_back();
}
if (mappings[node->val] < mappings[parent->val]) {
// left child
parent->left = node;
} else {
// right child
parent->right = node;
}
stack.push_back(node);
}
return root;
}
};
889. Construct Binary Tree from Preorder and Postorder Traversal
Recursive
class Solution {
public:
TreeNode* constructFromPrePost(vector<int>& pre, vector<int>& post) {
unordered_map<int, int> mappings;
for (int i = 0; i < post.size(); i += 1) { mappings[post[i]] = i; }
function<TreeNode*(int, int, int, int)> f =
[&](int pre_i, int pre_j, int post_i, int post_j) {
assert(pre_j - pre_i == post_j - post_i);
if (pre_i > pre_j) { return (TreeNode*)NULL; }
TreeNode* root = new TreeNode(pre[pre_i]);
if (pre_i == pre_j) { return root; }
int post_p = mappings[pre[pre_i + 1]];
int len_left = post_p - post_i + 1;
root->left =
f(pre_i + 1, len_left + (pre_i + 1) - 1, post_i, post_p);
root->right =
f(len_left + (pre_i + 1), pre_j, post_p + 1, post_j - 1);
return root;
};
return f(0, pre.size() - 1, 0, post.size() - 1);
}
};
1008. Construct Binary Search Tree from Preorder Traversal
Recursive
class Solution {
public:
TreeNode* bstFromPreorder(vector<int>& preorder) {
if (preorder.size() == 0) { return NULL; }
function<TreeNode*(int, int)> f = [&](int i, int j) {
if (i > j) { return (TreeNode*)NULL; }
TreeNode* root = new TreeNode(preorder[i]);
int r = i + 1;
while (r <= j && preorder[r] < root->val) { r += 1; }
root->left = f(i + 1, r - 1);
root->right = f(r, j);
return root;
};
return f(0, preorder.size() - 1);
}
};
we need O(n)
to get the next greater position r
, and this can be optimized using monotonic stack
class Solution {
public:
TreeNode* bstFromPreorder(vector<int>& preorder) {
if (preorder.size() == 0) { return NULL; }
vector<int> next_greater(preorder.size(), preorder.size());
vector<tuple<int, int>> monotonic_decreasing_stack;
for (int i = 0; i < preorder.size(); i += 1) {
while (!monotonic_decreasing_stack.empty() &&
get<0>(monotonic_decreasing_stack.back()) < preorder[i]) {
tuple<int, int> p = monotonic_decreasing_stack.back();
monotonic_decreasing_stack.pop_back();
next_greater[get<1>(p)] = i;
}
monotonic_decreasing_stack.push_back({preorder[i], i});
}
function<TreeNode*(int, int)> f = [&](int i, int j) {
if (i > j) { return (TreeNode*)NULL; }
TreeNode* root = new TreeNode(preorder[i]);
root->left = f(i + 1, min(j, next_greater[i] - 1));
root->right = f(next_greater[i], j);
return root;
};
return f(0, preorder.size() - 1);
}
};
can be further optimized into a 1-pass solution, 与其根据 preorder[i]
判断子树的范围,我们可以根据 lower_bound
与 upper_bound
来确定 preorder[curr]
是否属于当前子树
class Solution {
public:
TreeNode* bstFromPreorder(vector<int>& preorder) {
int curr = 0;
// 根据 `lower_bound` 与 `upper_bound` 返回从 `curr` 开始的子树
function<TreeNode*(int, int)> f = [&](int lower_bound,
int upper_bound) {
// `curr` not within bound, 说明从 `curr` 开始的元素不在当前子树中
if (curr == preorder.size() || preorder[curr] <= lower_bound ||
preorder[curr] >= upper_bound) {
return (TreeNode*)NULL;
}
TreeNode* node = new TreeNode(preorder[curr]);
curr += 1;
node->left = f(lower_bound, node->val);
node->right = f(node->val, upper_bound);
return node;
};
return f(INT32_MIN, INT32_MAX);
}
};
Iterative
首先注意几个 preorder traversal 的性质:
- if
to_node(preorder[i])->left != NULL
thento_node(preorder[i])->left == to_node(preorder[i + 1])
- when visiting some node, all its children should not have been visited
- when visiting
right_child
- parent and all parent's left children should have been visited
parent->val
is the greatest value less thanright_child->val
class Solution {
public:
TreeNode* bstFromPreorder(vector<int>& preorder) {
if (preorder.size() == 0) { return NULL; }
TreeNode* root = new TreeNode(preorder[0]);
// 如果我们用一个 monotonic decreasing stack,按 `preorder[].map(to_node)` 压入,那么可以保证
// - 如果栈顶结点的值大于当前节点值,那么栈顶结点是当前节点的 parent: `parent->left = node`
// - 自栈顶开始,最大的小于当前节点值的节点是当前节点的 parent:`parent->right = node`
vector<TreeNode*> stack = {root};
for (int i = 1; i < preorder.size(); i += 1) {
TreeNode* node = new TreeNode(preorder[i]);
TreeNode* parent = stack.back();
while (stack.size() > 0 &&
stack[stack.size() - 1]->val < node->val) {
parent = stack.back();
stack.pop_back();
}
if (node->val < parent->val) {
parent->left = node;
} else {
parent->right = node;
}
stack.push_back(node);
}
return root;
}
};
Construct binary tree from preorder and inorder traversal
Let's use here two facts:
- Binary tree could be constructed from preorder and inorder traversal.
- Inorder traversal of BST is an array sorted in the ascending order.