码迷,mamicode.com
首页 > 其他好文 > 详细

重建二叉树

时间:2021-02-20 12:10:36      阅读:0      评论:0      收藏:0      [点我收藏+]

标签:shm   索引   重建二叉树   排序   treenode   problems   操作   ||   存储   

一个二叉树的遍历序列不能决定一棵二叉树,但某些不同的遍历序列组合可以唯一确定一棵二叉树。

给定一棵二叉树的前序遍历序列和中序遍历序列可以唯一确定一棵二叉树的结构,给定一棵二叉树的后序遍历序列和中序遍历序列也可以唯一确定一棵二叉树的结构。

  注意:这还有一个条件:二叉树的任意两个结点的值都不相同

一. 根据前序遍历序列和中序遍历序列重建二叉树

原理:分治

  前序遍历性质: 节点按照 [ 根节点 | 左子树 | 右子树 ] 排序。
  中序遍历性质: 节点按照 [ 左子树 | 根节点 | 右子树 ] 排序。

根据以上性质,可得出以下推论:

  1. 前序遍历的 首元素 为树的根节点 node 的值。

  2. 在中序遍历中搜索根节点 node 的索引 ,可将 中序遍历 划分为 [ 左子树 | 根节点 | 右子树 ] 。

  3. 根据中序遍历中的左 / 右子树的节点数量,可将 前序遍历 划分为 [ 根节点 | 左子树 | 右子树 ] 。

按照上述步骤可以分出二叉树的左右子树,而对于子树的左右子树,也可同上进行划分。

由此考虑通过递归对所有子树进行划分,从而重建二叉树。

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode(int x) { val = x; }
 * }
 */
class Solution {
    int[] preorder;
    HashMap<Integer, Integer> map = new HashMap<>();
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        this.preorder = preorder;
        for(int i = 0; i < inorder.length; i++)
            map.put(inorder[i], i);
        return recur(0, 0, inorder.length-1);
    }
    TreeNode recur(int root, int left, int right) {
        if(left > right)
            return null;                          // 递归终止
        TreeNode node = new TreeNode(preorder[root]);          // 建立根节点
        int i = map.get(preorder[root]);                       // 划分根节点、左子树、右子树
        node.left = recur(root + 1, left, i - 1);              // 左子树递归
        node.right = recur(root + i - left + 1, i + 1, right); // 右子树递归
        return node;                                           // 回溯返回根节点
    }
}

PS: 使用哈希表 map 存储中序遍历的值与索引的映射,查找操作的时间复杂度为 O(1)

时间复杂度O(n),空间复杂度O(n)

参考:剑指 Offer 07. 重建二叉树

https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/solution/mian-shi-ti-07-zhong-jian-er-cha-shu-di-gui-fa-qin/

二、根据后序遍历序列和中序遍历序列重建二叉树

原理:

  后序遍历性质: 节点按照 [ 左子树 | 右子树 | 根节点 ] 排序。
  中序遍历性质: 节点按照 [ 左子树 | 根节点 | 右子树 ] 排序。

根据以上性质,可得出以下推论:

  1. 后序遍历的 尾元素 为树的根节点 node 的值。

  2. 在中序遍历中搜索根节点 node 的索引 ,可将 中序遍历 划分为 [ 左子树 | 根节点 | 右子树 ] 。

  3. 根据中序遍历中的左 / 右子树的节点数量,可将 后序遍历 划分为 [ 左子树 | 右子树 | 根节点 ] 。

类似 前中遍历重建二叉树 代码如下:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    int[] postorder;
    HashMap<Integer, Integer> map = new HashMap<>();
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        this.postorder = postorder;
        for(int i = 0; i < inorder.length; i++)
            map.put(inorder[i], i);
        return recur(0, postorder.length-1, 0, inorder.length-1);
    }
    TreeNode recur(int pS, int pE, int iS, int iE) {
        if(iE < iS || pE < pS)
            return null;                                        // 递归终止
        TreeNode node = new TreeNode(postorder[pE]);            // 建立根节点
        int i = map.get(postorder[pE]);                         // 划分根节点、左子树、右子树
        node.left = recur(pS, pS + i - iS - 1, iS, i-1);        // 左子树递归
        node.right = recur(pS + i - iS, pE - 1, i + 1, iE);     // 右子树递归
        return node;                                            // 回溯返回根节点
    }
}

 

重建二叉树

标签:shm   索引   重建二叉树   排序   treenode   problems   操作   ||   存储   

原文地址:https://www.cnblogs.com/zccfrancis/p/14416095.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!