047从前序与中序遍历序列构造二叉树
2026/5/17 2:19:51 网站建设 项目流程

从前序与中序遍历序列构造二叉树

题目链接:https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-inorder-traversal/description/?envType=study-plan-v2&envId=top-100-liked

我的解答:

分析:知道原理,但是实现上难以理清思路。

看了官方题解后的解答:

//方法一:递归 //时间复杂度:O(n) //空间复杂度:O(n) Map<Integer,Integer> map = new HashMap<>();//key:值 value:值在inorder中对应的下标 public TreeNode buildTree(int[] preorder, int[] inorder) { int n = preorder.length; //构造哈希映射,方便快速定位根节点在inorder中的位置 for(int i = 0; i < n; i++){ map.put(inorder[i], i); } return myBuildTree(preorder, inorder, 0, n-1, 0, n-1); } public TreeNode myBuildTree(int[] preorder, int[] inorder, int pLeft, int pRight, int iLeft, int iRight){ if(pLeft > pRight){ return null; } //前序遍历中的第一个节点就是根节点 TreeNode root = new TreeNode(preorder[pLeft]); //在中序遍历中定位根节点 int rootInInorder = map.get(preorder[pLeft]); //得到左子树中的节点数目 int leftCount = rootInInorder - iLeft; //递归地构造左子树,并连接到根节点 root.left = myBuildTree(preorder, inorder, pLeft+1, pLeft+leftCount, iLeft, rootInInorder-1); //递归地构造右子树,并连接到根节点 root.right = myBuildTree(preorder, inorder, pLeft+leftCount+1, pRight, rootInInorder+1, iRight); return root; } //方法二:迭代 //时间复杂度:O(n) //空间复杂度:O(n) public TreeNode buildTree(int[] preorder, int[] inorder) { Deque<TreeNode> stack = new LinkedList<>();//维护左子树还未构建完成的节点 TreeNode root = new TreeNode(preorder[0]); stack.push(root); int inorderIndex = 0; for(int i = 1; i < preorder.length; i++){ TreeNode top = stack.peek();//栈顶的节点 int topVal = top.val;//栈顶结点的值 TreeNode cur = new TreeNode(preorder[i]); if(topVal != inorder[inorderIndex]){//栈顶结点的左子树还未遍历完,当前节点应为栈顶结点的左孩子 top.left = cur; stack.push(cur); } else{//栈顶结点的左子树已经遍历完,当前节点应为栈顶结点或其某个祖先节点的右孩子 while(!stack.isEmpty() && stack.peek().val == inorder[inorderIndex]){ top = stack.pop(); inorderIndex++; } top.right = cur; stack.push(cur); } } return root; }

分析:

​ 1、方法一的解题思路:利用哈希表预处理中序遍历数组,方便快速定位计算左、右子树节点总数。每次维护当前节点作为根节点的子树在前序遍历和中序遍历中的范围,在范围内,第一个节点就是当前子树的根节点,创建出根节点,继续递归构造当前根节点的左子树和右子树即可。

​ 2、方法二的解题思路:利用栈维护还未构建右子树的节点,遍历前序遍历数组,创建出当前节点,当前节点只有两种情况:

​ 情况一:当前栈顶节点的值与中序遍历的值不相等,那么当前节点就是栈顶结点的左孩子;

​ 情况二:当前栈顶节点的值与中序遍历的值相等,那么当前节点是栈顶结点或栈顶某个祖先节点的右孩子。

​ 对于情况一,我们直接将当前节点作为栈顶结点的左孩子并将当前节点入栈即可;

​ 对于情况二,栈顶节点的值出现在中序遍历,意味着栈顶结点的左子树已经构造完成,所以当前节点要么是栈顶结点的右孩子,要么是栈顶某个祖先节点的右孩子,我们只需要不断从栈中弹出所有左子树已经构建完成的节点,最后弹出的那个节点就是当前节点的父节点。我们只需要将当前节点作为最后弹出的那个节点的右孩子并将当前节点入栈即可。

总结

  • 本题主要有递归和迭代两种方法解题。
  • 对于递归方法:只需要维护每个节点作为根节点时,整棵树的节点分别在前序遍历和中序遍历的范围;再利用栈预处理中序遍历,方便快速定位当前节点的位置,并迅速计算出当前节点的左子树节点总数和右子树节点总数。
  • 对于迭代方法:用栈维护左子树未构建完成的节点,先构建出二叉树的根节点并入栈,然后从下标1开始遍历前序遍历数组,根据前序遍历的特点,当前节点要么是栈顶结点的左孩子,要么是栈顶结点或栈顶某个祖先节点的右孩子,我们可以结合中序遍历来判断当前节点是属于哪种情况,根据中序遍历的特点,若栈顶结点出现在中序遍历,那么意味着栈顶结点的左子树已经构建完成,我们弹出栈中所有左子树已经构建完成的节点,当前节点就是最后弹出的那个节点的右孩子。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询