排序二叉树的中序遍历序列是有序序列_(Trivial) LeetCode 105—从前序与中序遍历序列构造二叉树

关键字:树,递归算法

归航return:(Trivial) LeetCode 289—生命游戏​zhuanlan.zhihu.com
归航return:LeetCode 336—回文对​zhuanlan.zhihu.com

Problem

Given preorder and inorder traversal of a tree, construct the binary tree.

Note: You may assume that duplicates do not exist in the tree.

For example, given

preorder = [3,9,20,15,7]
inorder = [9,3,15,20,7]

Return the following binary tree:

3
   / 
  9  20
    /  
   15   7
105. 从前序与中序遍历序列构造二叉树 - 力扣(LeetCode)​leetcode-cn.com

Solution

这道题目是一道很基础的二叉树问题,要求从前序遍历和中序遍历中,复原一个二叉树。要解决这个问题,首先要回归到这两种遍历方法的定义上来。

前序遍历:如果当前节点不为空:那么:(1)访问当前节点(2)递归地访问当前节点的左子树(3)递归地访问当前节点的右子树;

中序遍历:如果当前节点不为空,那么:(1)递归地访问当前节点的左子树(2)访问当前节点(3)递归地访问当前节点的右子树。

因此,我们可以将访问得到的结果当成三个部分,对于前序遍历来说,就是:[current, left, right],对于中序遍历来说,就是 [left, current, right],而 current 因为只有一个元素而且是前序遍历范围中的开头元素,因此是相对好确定的位置。因为题目假设 duplicates do not exist in the tree,因此可以使用哈希表的方法,预先存储中序遍历结果的元素和下标的位置关系,这样就可以很容易地从 current,也就是前序遍历的开头,快速地找到分界点的位置。又因为我们这里需要存储 leftright 在数组中下标的位置,因此还需要递归函数中包含四个额外变量,分别对应这两个区间的范围。按照我的习惯,我习惯使用左闭右开区间,因为这样可以让代码更加统一,更难出错。C++ 的 STL 中,大量的算法,定义都是使用的左开右闭区间。我相信,没有人比标准库的开发者更懂这些基础算法的优化细节。

代码如下:

class Solution {
    HashMap<Integer, Integer> inorderHashMap;
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if (preorder.length == 0){
            return null;
        }
        inorderHashMap = new HashMap<>();
        for (int i = 0; i < inorder.length; ++i){
            inorderHashMap.put(inorder[i], i);
        }
        return buildTreeHelper(preorder, 0, preorder.length, 0, inorder.length);
    }
    private TreeNode buildTreeHelper(int[] preorder, int preorderLeft, int preorderRight, int inorderLeft, int inorderRight){
        if (preorderLeft == preorderRight){
            return null;
        }
        TreeNode ret = new TreeNode(preorder[preorderLeft]);
        int idx = inorderHashMap.get(ret.val);
        ret.left = buildTreeHelper(preorder, preorderLeft+1, preorderLeft+1+(idx-inorderLeft), inorderLeft, idx);
        ret.right = buildTreeHelper(preorder, preorderRight-(inorderRight-idx-1), preorderRight, idx+1, inorderRight);
        return ret;
    }
}

这里递归参数虽然有四个,但是因为子树无论是如何遍历,节点的个数是相等的,因此在我们的递归调用中 preorderRight-preorderLeft == inorderRight-inorderLeft,这样可以减少思维量。

涉及到递归的算法通常比较难估计,不过考虑极端情况,就是二叉树退化成链表,这个时候的时间复杂度是 O(N),空间复杂度,包括栈调用的复杂度,就是 O(N),其中 N 是二叉树中,节点的个数。

EOF。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值