剑指offer题解// 4·重建二叉树

题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

关键词:二叉树

题目理解

二叉树顺序存储之 前序,中序 ,后序遍历

遍历规则:(根据根节点的位置来确定是,前序、中序、后序)

前序遍历为:根节点——左子树——右子树
中序遍历为:左子树——根节点——右子树
后序遍历为:左子树——右子树——根节点
层序遍历为:把一棵树从上到下,从左到右依次写出来

在这里插入图片描述
前序遍历为:(4,7,9,2,1,5,6)
中序遍历为:(7,9,4,1,2,6,5)
后序遍历为:(9,7,1,6,5,2,4)

题目要求:重建(输出root所对应的借点)

题解

原理

根据中序遍历和前序遍历可以确定二叉树,具体过程为:

  1. 根据前序序列第一个结点确定根结点
  2. 根据根结点在中序序列中的位置分割出左右两个子序列
  3. 对左子树和右子树分别递归使用同样的方法继续分解

例如

前序序列{1,2,4,7,3,5,6,8} = pre
中序序列{4,7,2,1,5,3,8,6} = in

  1. 根据当前前序序列的第一个结点确定根结点,为 1
  2. 找到 1 在中序遍历序列中的位置,为 in[3]
  3. 切割左右子树,则 in[3] 前面的为左子树, in[3] 后面的为右子树
  4. 则切割后的左子树前序序列为:{2,4,7},切割后的左子树中序序列为:{4,7,2},切割后的右子树前序序列为:{3,5,6,8},切割后的右子树中序序列为:{5,3,8,6}
  5. 对子树分别使用同样的方法分解

代码实现

链接:https://www.nowcoder.com/questionTerminal/8a19cbe657394eeaac2f6ea9b0f6fcf6?answerType=1&f=discussion
来源:牛客网

/**
 * Definition for binary tree  
 * 二叉树结构:
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
import java.util.Arrays;
public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {

		// (选择)判断是否为空数组
        if (pre.length == 0 || in.length == 0) {
            return null;
        }
        // (顺序)前序的第一个点是根节点
        TreeNode root = new TreeNode(pre[0]);
        
        // (循环)在中序长度
        // (选择)找到前序的根
        // (顺序)重复操作,找到子树前序的根
        for (int i = 0; i < in.length; i++) {
        
            if (in[i] == pre[0]) {
                // 左子树,注意 copyOfRange 函数,左闭右开
                root.left = reConstructBinaryTree(Arrays.copyOfRange(pre, 1, i + 1), Arrays.copyOfRange(in, 0, i));
                // 右子树,注意 copyOfRange 函数,左闭右开
                root.right = reConstructBinaryTree(Arrays.copyOfRange(pre, i + 1, pre.length), Arrays.copyOfRange(in, i + 1, in.length));
                break;
            }
        }
        return root;
    }
}

另一种递归

原理

1、通过前序序列第一个元素确定根节点(例如 1)。

2、通过根节点把中序序列分成两个序列,一个是左子树序列([4,7,2)],一个是右子树序列([5,3,8,6)]。

3、通过左右子树的中序序列可以求出前序遍历的左右子树序列(左:[2,4,7],右:[3,5,8,6])。

4、左右子树的前序序列第一个元素分别是根节点的左右儿子。

5、通过递归重复以上步骤

代码实现

    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
 		
 		// (选择)判断是否为空数组
        TreeNode root;
        root = rebuildTree(pre, 0, pre.length - 1, in, 0, in.length - 1);
        return root;
    }
    // preStart-preEnd表示前序序列的起始位置,inStart-inEnd也一样
    private TreeNode rebuildTree(int[] pre, int preStart, int preEnd, int[] in, int inStart, int inEnd) {
        if(preStart > preEnd | inStart > inEnd)
            return null;
        // 根节点
        TreeNode root = new TreeNode(pre[preStart]);
        // 寻找根节点在中序序列的位置
        for (int i = inStart; i <= inEnd; i++) {
            if (in[i] == pre[preStart]) {
                // 可以计算出中序序列的左右子树序列为:左:inStart~i -1,右:i+1~inEnd。
                // 前序序列的左右子树:左:preStart+1~preStart+i-inStart,右:preStart+i-inStart+1~preEnd
                root.left = rebuildTree(pre,preStart+1, preStart+i-inStart,in, inStart, i - 1);
                root.right = rebuildTree(pre,preStart+i-inStart+1, preEnd, in, i+1, inEnd);
            }
        }
        return root;
    }

总结

二叉树——重建二叉树
1.前序遍历+中序遍历 => 重建二叉树
2.中序遍历+后序遍历 => 重建二叉树
3.前序遍历+后序遍历 => 无法确定二叉树

4·二叉树的遍历方式简单来说有3种方式,前,中,后序遍历,一般采用递归算法,有的可能还存在所谓的层次遍历,就是一层一层的遍历;

5·其实要记忆这东西也很简单,遍历的顺序都是根据根节点的位置来的,根节点在第一个就是前序,根节点在第二位就是中序,根节点在第三位就是后续;

6·注意 copyOfRange 函数,左闭右开

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值