【剑指offer 07】重建二叉树(Java)

【题目描述】
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
限制:0 <= 节点个数 <= 5000

【样例示例】
给出

  • 前序遍历:preorder = [3,9,20,15,7]
  • 中序遍历:inorder = [9,3,15,20,7]

返回如下的二叉树:
在这里插入图片描述
【解题思路】
树节点遍历的性质有三种:前中后序

  • 前序遍历顺序:根节点 => 左节点 => 右节点
  • 中序遍历顺序:左节点 => 根节点 => 右节点
  • 后序遍历顺序:左节点 => 右节点 => 根节点
  1. 根据上述的性质,前序数组第一个元素preorder[0]就是树的根节点。
  2. 知道了根节点,就可以根据中旬遍历结果划分左右子树了,在根节点左边的就是树的左子树,根节点右边的是树的右子树。例如上面给出的样例中,根节点就是3,在inorder数组中,3左边的就是左子树的结点,3右边的是右子树的所有节点。
  3. 基于以上,采用递归获取树的其余节点

class TreeNode {
    
    
	int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) {
    
     val = x; }
 }

public class Solution {
    
    
	
    int[] preorder;	// 存放前序遍历结果
    HashMap<Integer, Integer> dic = new HashMap<>();// 存放中序遍历结果

    public TreeNode buildTree(int[] preorder, int[] inorder) {
    
    
        
        this.preorder = preorder;

        for(int i = 0; i < inorder.length; i++)
            dic.put(inorder[i], i);
        
        return back(0, 0, inorder.length - 1);
    }
    
    public TreeNode back(int root, int left, int right) {
    
    
    	//递归结束条件
        if(left > right)
        	return null;
        // 根节点
        TreeNode node = new TreeNode(preorder[root]);
        // 在中序遍历数组中找到根节点位置,并以此划分左右子树
        int i = dic.get(preorder[root]);
        // 左子树递归
        node.left = back(root + 1, left, i - 1);
        // 右子树递归
        node.right = back(root + i - left + 1, i + 1, right);
        // 返回根节点
        return node;
    }
}

需要注意的地方:
左子树递归的划分比较好理解,左子树的根节点看前序遍历数组,就是左子树的第一个root+1,左边边界就是left,右边边界是中间区分的i-1
右子树的根节点可能难理解一点,其实右子树的根也是看前序遍历数组,就是右子树的第一个,即当前根节点加上左子树的数量

  • 左子树的数量 = 左子树的右边 - 左边 =i-1-left+1 = i-left
  • 右子树的根 = 当前根节点+左子树数量+1 = root+i-left+1

所以右子树第一个根是 root+i-left+1,左边边界是i+1 ,右边边界是 right

参考文章:

重建二叉树(递归法,清晰图解)

猜你喜欢

转载自blog.csdn.net/qq_42908549/article/details/112849947