第7题:重建二叉树

该博客介绍了如何通过前序和中序遍历的结果来重建二叉树。解题关键在于前序遍历找到根节点,中序遍历划分左右子树,采用递归分治策略。在构建树的过程中,利用HashMap存储中序遍历的值及其索引,从而确定子树的边界并递归构造左右子树。
摘要由CSDN通过智能技术生成


文章参考

1. 题目描述

在这里插入图片描述

  • preorder:前序。inorder:中序。postorder:后序。
  • 输出结果就是 从上至下,从左至右,9没有孩子所以null。

2. 解题思路

  • 首先知道前序遍历:根左右。中序:左根右
  • 根据以上性质可以推断:
    • 前序时第一个是根节点
    • 根据前序结果,在中序时候,搜索根节点可以划分左右子树
    • 根据划分的子树中节点数,可以把前序结果划分为 根 | 左子树 | 右子树

在这里插入图片描述

根据上面三步,可以确定3个节点:1.根节点 2.左子树根节点 3.右子树根节点
使用分治,对左右子树递归求解

分析:
	递推参数:
		根节点前序遍历索引(只有前序才能确定根节点) root
		子树在中序遍历的范围(左边界) left	(只有中序才能依据根节点划分左右子树)
	    子树在中序遍历的范围(右边界) right

	终止条件:left > right,表示中序依据根节点划分结束了,没有左右子树了 return null
	
	步骤:
		1. 建立根节点 node:节点值 = preorder[root],前序[索引] = 根节点值
		2. 划分左右子树:查找根节点在中序的索引i,i左边为左子树,i右边为右子树。
		3. 使用hash建立中序遍历 值和索引的映射
		4. 递归构造左右子树

	注意:
-----------------------------------------------------------------------------------------------
	
				根节点索引(前序条件下)				中序遍历左边界			中序遍历右边界
				
	左子树		root + 1							left(默认0索引,从头开始)	i - 1
				(前序:根右边就是左子树,但不知长度)

	右子树		root +(i-left)+ 1					i+1(i是中序根索引)		    right(默认最后一个索引)
				(i-left)= 左子树长度,注意
				不是个数,而是长度,1-3个数有3个数,
				长度是2
			
-----------------------------------------------------------------------------------------------	
	重点:
		1. 前序中,根+左子树长度+1 = 右子树根索引:如根=0,左子树长度1,则0+1+1=2=右子树索引
		2. 前序只能知道根节点,左子树根节点,而不知道边界(即左右子树长度)
		3. 中序才能获取左右子树边界条件
				

	

在这里插入图片描述

总结:前序找根,中序划分 !!!

  • 前序找每次需要的根节点,然后依据中序划分子树的左右。

3. 代码

/**
 * 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> map = new HashMap<>();//标记中序遍历!

    //保留的先序遍历,方便递归时依据索引查看先序遍历的值
    // 之所以保留是因为,前序才能获取每个子树的根节点!!!!!!
    int[] preorder;
    

    public TreeNode buildTree(int[] preorder, int[] inorder) {
        this.preorder = preorder;	// 备份前序结果,参考上面原因
        
        //将中序遍历的值及索引放在map中,方便递归时获取左子树与右子树的数量及其根的索引
        // 值是key,索引是value
        for (int i = 0; i < inorder.length; i++) {
            map.put(inorder[i], i);
        }
        
        //三个索引分别为,这三个数是规定好的,因为本题求解的是完整的树,需要从头开始。
        //当前根的的索引(前序找根,第一个根就是0索引元素)
        //递归树的左边界,即数组左边界(中序划分)
        //递归树的右边界,即数组右边界(中序划分)
        return recursive(0,0,inorder.length-1);
    }


	 /**
	     * @param pre_root_idx  先序遍历的索引
	     * @param in_left_idx  中序遍历的索引
	     * @param in_right_idx 中序遍历的索引
	     */
    TreeNode recursive(int pre_root_idx, int in_left_idx, int in_right_idx){
    	
    	// 所以in_left 默认0索引,从头开始,in_right = 节点个数-1(索引)
        if(in_left_idx > in_right_idx) return null;// 相等的话就是自己
        
        //构造root节点,preorder[pre_root_idx]是根值
        TreeNode root = new TreeNode(preorder[pre_root_idx]);
        

         // 获取在中序遍历中根节点所在索引,以方便获取左子树的数量
         // map是中序的
         // preorder[pre_root] 是前序根的值 = 根的值,再拿根值获得中序根索引
        int idx = map.get(preorder[pre_root_idx]);
      
        //左子树的根的索引为先序中的根节点+1  = pre_root_idx + 1,第一个参数都是根节点,所以由前序给出
        //递归左子树的左边界为原来的中序 in_left_idx 
        //递归左子树的右边界为中序中的根节点索引-1 = idx - 1
        // 再把返回的节点赋给root左孩子
        root.left = recur(pre_root_idx + 1, in_left_idx, idx - 1);
        
        //右子树的根的索引为先序中的 当前根位置 + 左子树的数量 + 1
        //递归右子树的左边界为中序中当前根节点+1
        //递归右子树的右边界为中序中原来右子树的边界
        root.right = recur(pre_root_idx + (idx - in_left_idx) + 1, idx+1, in_right_idx);
        return root;

    }

}

4. 心得体会

  • 分治法
  • 树形结构分左右,一般分成左右的都可以考虑分治
  • 前序找根,中序划分!!!!!!!!!!
  • 步骤
    • 保留先序找根;创建字典。
    • 备份先序;put字典;return(0,0,length-1)
    • 推出条件left>right;创建节点root;中序找根索引idx;root.left=;root.right=;返回root(其实是一个node,可以看成每次都是父节点)。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值