网络异常,图片无法展示
|
给定一棵树的前序遍历 preorder
与中序遍历 inorder
。请构造二叉树并返回其根节点。
示例 1:
网络异常,图片无法展示
|
Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7] Output: [3,9,20,null,null,15,7] 复制代码
示例 2:
Input: preorder = [-1], inorder = [-1] Output: [-1] 复制代码
提示:
1 <= preorder.length <= 3000
inorder.length == preorder.length
-3000 <= preorder[i], inorder[i] <= 3000
preorder
和inorder
均无重复元素inorder
均出现在preorder
preorder
保证为二叉树的前序遍历序列inorder
保证为二叉树的中序遍历序列
本题解题思路如下:
- 前序遍历的顺序为根左右,中序遍历的顺序为左根右,所以
preorder[0]
为当前子树根节点的值 - 查找该值在
inorder
中的位置,其左边即为左子树中序遍历序列,右边为右子树中序遍历序列 - 获取到左右子树中序遍历后,因为子树前序遍历和中序遍历的结果只是顺序不同,但是序列长度是相同的,所以可以根据左子树中序遍历序列长度去
preorder
获取左子树前序遍历序列,剩余部分即为右子树前序遍历序列 - 然后就可以通过根节点的值创建根节点,根据左右子树的前序、中序遍历序列递归创建左右子树
- 最后返回二叉树的根节点即可
动画演示如下:
网络异常,图片无法展示
|
第一版代码如下:
var buildTree = function(preorder, inorder) { // 如果前序遍历序列为空,返回空 if(preorder.length === 0) return null; // 创建子树根节点 const root = new TreeNode(preorder.shift()), // 获取根节点值在中序遍历序列的下标 ind = inorder.indexOf(root.val); // 通过根节点值在中序遍历序列的下标,截取左子树前序遍历,中序遍历序列,创建左子树 root.left = buildTree(preorder.splice(0,ind),inorder.splice(0,ind)); // 根据剩余部分截取右子树前序遍历,中序遍历序列,创建右子树 root.right = buildTree(preorder,inorder.splice(1)); // 返回根节点 return root; }; 复制代码
这一版代码提交通过后,只击败了 50%
左右的用户,是因为在递归过过程需要截取左右子树的前序、中序遍历序列,这样的操作增加了执行用时和空间复杂度。
这里我们可以通过维护当前子树前序遍历序列开始结束下标,及中序遍历序列开始结束下标代替截取前序、中序遍历序列的操作,同样达到递归构建左右子树的目的。
优化后代码如下:
var buildTree = function(preorder, inorder) { // 传入前序遍历序列开始下标,结束下标,中序遍历序列开始下标 function build(preStart,preEnd,inStart){ // 如果前序遍历序列开始下标大于结束下标,说明区间处理完成,返回 null if(preStart>preEnd) return null; // 通过前序遍历开始下标值构建根节点 const root = new TreeNode(preorder[preStart]), // 获取根节点值在中序遍历序列的下标 ind = inorder.indexOf(root.val), // 获取中序遍历左子树的长度 leftSize = ind-inStart; // 递归的构建左右子树 root.left = build(preStart+1,preStart+leftSize,inStart); root.right = build(preStart+leftSize+1,preEnd,ind+1); return root; } // 返回构建后二叉树的根节点 return build(0,preorder.length-1,0) }; 复制代码
至此我们就完成了 leetcode-105-从前序与中序遍历序列构造二叉树
如有任何问题或建议,欢迎留言讨论!