LeetCode剑指offer——重建二叉树

描述

给定节点数为 n 的二叉树的前序遍历和中序遍历结果,请重建出该二叉树并返回它的头结点。

例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建出如下图所示。

提示:

1.vin.length == pre.length

2.pre 和 vin 均无重复元素

3.vin出现的元素均出现在 pre里

4.只需要返回根结点,系统会自动输出整颗树做答案对比

数据范围:n ≤ 2000,节点的值 -10000 ≤ val ≤ 10000

要求:空间复杂度 O(n),时间复杂度 O(n)

示例1

输入:

[1,2,4,7,3,5,6,8],[4,7,2,1,5,3,8,6]

返回值:

{1,2,3,4,#,5,6,#,7,#,#,8}

示例2

输入:

[1],[1]

返回值:

{1}

复制

示例3

输入:

[1,2,3,4,5,6,7],[3,2,4,1,6,5,7]

返回值:

{1,2,5,3,4,6,7}

说明:

返回根节点,系统会输出整颗二叉树对比结果,重建结果如题面图示  

java构建的二叉树

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

算法思想一:递归

解题思路:

二叉树的前序遍历:左右;中序遍历:左根右
由前序遍历知道根节点之后,能在中序遍历上划分出左子树和右子树。分别对中序遍历的左右子树递归进行这一过程即可建树。
 

解:

public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] vin) {
        if(pre.length==0||vin.length==0)
            return null;
        TreeNode result = new TreeNode(pre[0]);
        for(int i = 0;i<vin.length;i++)
        {
            if(vin[i]==pre[0]){
                result.left = reConstructBinaryTree( Arrays.copyOfRange(pre,1,i+1), Arrays.copyOfRange(vin,0,i));
                result.right = reConstructBinaryTree(Arrays.copyOfRange(pre,i+1,pre.length),Arrays.copyOfRange(vin,i+1,vin.length));
                break;  
            }
        }
        return result;
    }
    
}

算法思想二:指针

解题思路:

二叉树的前序遍历:左右;中序遍历:左根右

设置三个指针,一个是preStart,表示的是前序遍历开始的位置,一个是inStart,表示的是中序遍历开始的位置。一个是inEnd,表示的是中序遍历结束的位置,我们主要是对中序遍历的数组进行拆解

图解:

前序序列:【1,2,3,4,5,6,7】

中序遍历:【3,2,4,1,6,5,7】

只要找到了前序遍历的结点在中序遍历的位置,我们就可以把中序遍历数组分解为左右子树两部分。

1、中序序列的划分

如果index是前序遍历的某个值在中序遍历数组中的索引,以index为根节点划分,在中序遍历中,[0,index-1]就是根节点左子树的所有节点,[index+1,tin.length-1]就是根节点右子树的所有节点

2、前序序列的划分

左子树

对于前序序列,针对左子树,preStart=index+1,如果是右子树就稍微麻烦点,

右子树

  • 前序序列是 根->左->右

故,右子树的位置就是从根节点开始走过左子树,然后左子树的下一个节点就是右子树的第一个节点

公式表示:

  1. (根节点的位置)+(左子树的数量)+1
  2. 根节点的位置=preStart
  • 中序序列是 左->右->根

根据这个原理,左子树的数量可以从中序遍历里找,

即:找到中序遍历中根节点的位置,根节点的左边有多少元素,左子树就有几个节点。

公式表示:

       3. (index-inStart)
结合 2,3, 公式1表示为

preStart+ (index-inStart)+ 1 

public class Solution {
    public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
        return dfs(0, 0, in.length - 1, pre, in);
    }
    
    public TreeNode dfs(int preStart, int inStart, int inEnd, int[] preorder, int[] inorder) {
        if (preStart > preorder.length - 1 || inStart > inEnd) {
            return null;
        }
        //创建结点
        TreeNode root = new TreeNode(preorder[preStart]);
        int index = 0;
        //找到当前节点root在中序遍历中的位置,然后再把数组分两半
        for (int i = inStart; i <= inEnd; i++) {
            if (inorder[i] == root.val) {
                index = i; break; 
            } 
        } 
        root.left = dfs(preStart + 1, inStart, index - 1, preorder, inorder); 
        root.right = dfs(preStart + index - inStart + 1, index + 1, inEnd, preorder, inorder); 
        return root; 
    }
}
  • 算法示意图来自牛客,侵删,这两篇有点深,对于初学者不太友好,至少得知道数据结构-树,深度优先遍历等知识,没看明白多看几遍,也可以私信我!

猜你喜欢

转载自blog.csdn.net/qq_44431331/article/details/123790347