题目描述
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
限制:0 <= 节点个数 <= 5000
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。
解题思路
前序遍历是【根左右】,中序遍历是【左根右】,那么对于preorder[]来说,首位便是根节点,再由于无重复的val,就可以再inorder[]里定位到此根节点,inorder[]根节点左边的节点数就是左子树的节点数,记为 l n l_n ln,右边的节点数就是右子树的节点数 r n r_n rn。那么反过来再关注preorder[],根节点后的 l n l_n ln个节点就为左子树的节点,剩下的就是右子树的节点。
代码详解
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
HashMap<Integer, Integer> hs = new HashMap<>(); // 中序遍历里的{val, 下标}
public TreeNode buildTree(int[] preorder, int[] inorder) {
int len = preorder.length;
if(len == 0) {
return null;
}
for(int i = 0; i < len; ++i) {
hs.put(inorder[i], i);
}
return func(preorder, inorder, 0, len-1, 0, len-1); // 建立树
}
public TreeNode func(int[] preorder, int[] inorder, int pre_left, int pre_right, int in_left, int in_right) {
if(pre_left > pre_right) {
return null;
}
int in_mid = hs.get(preorder[pre_left]); // 在中序遍历数组中找到当前子树的根节点
TreeNode root = new TreeNode(preorder[pre_left]); // 建立根
int left_num = in_mid - in_left; // 确定当前子树的左子树节点个数
// 建立左子树
root.left = func(preorder, inorder, pre_left+1, pre_left+left_num, in_left, in_mid-1);
// 建立右子树
root.right = func(preorder, inorder, pre_left+left_num+1, pre_right, in_mid+1, in_right);
return root;
}
}
注意点
- 正是由于节点的val各不相同,才有可能定位左右子树的范围