https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
https://leetcode.cn/problems/construct-binary-tree-from-inorder-and-postorder-traversal/
前序+中序
-
前序遍历,节点按照
[根左右]
排序。 -
中序遍历,节点按照
[左根右]
排序。
所以,确定某根后,可以根据中序遍历判断该根的左右节点区间
。
通过结合前序遍历(确定根)
和中序遍历(确定根的左右子树)
,可以构造出二叉树。
class Solution {
public:
int n, idx;
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
TreeNode* root = nullptr;
n = inorder.size();
return dfs(root, preorder, inorder, 0, n - 1);
}
// 获取根在中序遍历中的下标
int index(int v, vector<int>& inorder) {
for(int i = 0; i < n; i++)
if(v == inorder[i])
return i;
return -1;
}
TreeNode* dfs(TreeNode* root, vector<int>& preorder, vector<int>& inorder, int l, int r) {
if(l > r)
return nullptr;
int v = preorder[idx++];
int ind = index(v, inorder);
// 前序:根左右。和idx++同向
// 中序:左根右。
// 下面初始化时也是先左后右,和idx++同向
root = new TreeNode(v);
root->left = dfs(root->left, preorder, inorder, l, ind - 1);
root->right = dfs(root->right, preorder, inorder, ind + 1, r);
return root;
}
};
中序+后序
和上面类似。
-
后序遍历,节点按照
[左右根]
排序。 -
中序遍历,节点按照
[左根右]
排序。
所以,确定某根后,也可以根据中序遍历判断该根的左右节点区间
。
代码区别也不大,需要注意的是idx
的初值和构造顺序。后序遍历根是从后往前,即根右左
,所以构造时也要符合这个顺序,先初始化右
再初始化左
。
class Solution {
public:
int idx, n;
TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
// idx初始值
idx = n = inorder.size();
TreeNode *root;
return dfs(root, postorder, inorder, 0, n - 1);
}
// 获取根在中序遍历中的下标
int index(int v, vector<int>& inorder) {
for(int i = 0; i < n; i++)
if(v == inorder[i])
return i;
return -1;
}
TreeNode* dfs(TreeNode* root, vector<int>& postorder, vector<int>& inorder, int l, int r) {
if(l > r)
return nullptr;
int v = postorder[--idx];
int ind = index(v, inorder);
// 后序:左右根。和idx++同向
// 中序:左根右。
// 下面初始化时要按照先右后左的顺序,和idx++同向
root = new TreeNode(v);
root->right = dfs(root->right, postorder, inorder, ind + 1, r);
root->left = dfs(root->left, postorder, inorder, l, ind - 1);
return root;
}
};