[剑指Offer]重建二叉树(Java)

剑指Offer题目

重建二叉树 -- 剑指Offer 4

 

题目描述

 * 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。
 * 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
 * 
 * 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},
 * 则重建二叉树并返回。

 

思路

     * 1、前序遍历序列中的第一个元素为根节点
     * 2、找到该根节点在中序遍历序列中的位置,左侧即为左树的遍历序列,右侧为右树的遍历序列
     * 3、根据左树遍历序列的数组长度len,找出前序遍历序列的第2到第len+1个元素,第一个元素即为左树中的根节点,右树的根节点是前序遍历序列的最后一个节点
     * 4、递归进行上述过程,构建树

 

代码

package com.my.test.codinginterviews;

/**
 * 题目:
 * 重建二叉树 -- 剑指Offer 4
 * 
 * 
 * 题目描述:
 * 输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。
 * 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
 * 
 * 例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},
 * 则重建二叉树并返回。
 */
public class ReConstructBinaryTree
{
    static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        TreeNode(int x) { val = x; }
    }   
    
    
    /**
     * 思路: 
     * 1、前序遍历序列中的第一个元素为根节点
     * 2、找到该根节点在中序遍历序列中的位置,左侧即为
     *    左树的遍历序列,右侧为右树的遍历序列
     * 3、根据左树遍历序列的数组长度len,找出前序遍历
     *       序列的第2到第len+1个元素,第一个元素即为左树中的根节点,
     *    右树的根节点是前序遍历序列的最后一个节点
     * 4、递归进行上述过程,构建树
     */    
    public TreeNode reConstructBinaryTree(int [] pre, int [] in) {
        if (pre == null || in == null) {
            // empty param
            return null;
        }
        
        int preLen = pre.length;
        int inLen = in.length;
        
        if (preLen != inLen) {
            // inValid param
            return null;
        }
        
        // 只有一个元素
        if (preLen == 1) {
            return new TreeNode(pre[0]);
        }
        
        return buildTree(pre, 0, preLen-1, in, 0, inLen-1);
    }
    
    private TreeNode buildTree(int[] preOrder, int preBegin, int preEnd, 
                                int[] inOrder, int inBegin, int inEnd) {
        if (preBegin > preEnd || inBegin > inEnd) {
            return null;
        }
        
        // 1、根节点的值
        int rootVal = preOrder[preBegin];
        
        // 2、找到该值在中序序列中的索引      
        int rootIdxInOrder = -1;
        for (int i=inBegin; i<= inEnd; i++) {
            if (inOrder[i] == rootVal) {
                rootIdxInOrder = i;
                break;
            }
        }
        // 没找到,参数不合法,返回null
        if (rootIdxInOrder < 0) {
            return null;
        }

        // 3、生成头节点
        TreeNode root = new TreeNode(rootVal);
        
        // 只有一个元素,直接返回,减少递归层次
        if (preBegin == preEnd && inBegin == inEnd) {
            return root; 
        }
        
        // 4、左子树长度
        int leftTreeLen = rootIdxInOrder - inBegin;
        
        // 5、前序遍历序列中,左子树遍历序列结束索引为preBegin + 1 + leftTreeLen - 1
        int preIdxLeftTreeEnd = preBegin + leftTreeLen;
        
        // 6、递归处理左右子树,挂接左右节点, 要去掉当前根节点的索引
        root.left = buildTree(preOrder, preBegin+1, preIdxLeftTreeEnd, 
                                inOrder, inBegin, rootIdxInOrder-1);
        root.right = buildTree(preOrder, preIdxLeftTreeEnd+1, preEnd, 
                                inOrder, rootIdxInOrder+1, inEnd);
        
        return root;
    }
	
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值