【问题描述】[中等]
根据一棵树的前序遍历与中序遍历构造二叉树。注意:
你可以假设树中没有重复的元素。例如,给出前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:3/ \9 20/ \15 7
【解答思路】
1. 递归
先序遍历的顺序是根节点,左子树,右子树。中序遍历的顺序是左子树,根节点,右子树。
只需要根据先序遍历得到根节点,然后在中序遍历中找到根节点的位置,它的左边就是左子树的节点,右边就是右子树的节点。
时间复杂度:O(N) 空间复杂度:O(N)
public TreeNode buildTree(int[] preorder, int[] inorder) {return buildTreeHelper(preorder, 0, preorder.length, inorder, 0, inorder.length);
}private TreeNode buildTreeHelper(int[] preorder, int p_start, int p_end, int[] inorder, int i_start, int i_end) {// preorder 为空,直接返回 nullif (p_start == p_end) {return null;}int root_val = preorder[p_start];TreeNode root = new TreeNode(root_val);//在中序遍历中找到根节点的位置int i_root_index = 0;for (int i = i_start; i < i_end; i++) {if (root_val == inorder[i]) {i_root_index = i;break;}}int leftNum = i_root_index - i_start;//递归的构造左子树root.left = buildTreeHelper(preorder, p_start + 1, p_start + leftNum + 1, inorder, i_start, i_root_index);//递归的构造右子树root.right = buildTreeHelper(preorder, p_start + leftNum + 1, p_end, inorder, i_root_index + 1, i_end);return root;
}
HashMap优化
public TreeNode buildTree(int[] preorder, int[] inorder) {HashMap<Integer, Integer> map = new HashMap<>();for (int i = 0; i < inorder.length; i++) {map.put(inorder[i], i);}return buildTreeHelper(preorder, 0, preorder.length, inorder, 0, inorder.length, map);
}private TreeNode buildTreeHelper(int[] preorder, int p_start, int p_end, int[] inorder, int i_start, int i_end,HashMap<Integer, Integer> map) {if (p_start == p_end) {return null;}int root_val = preorder[p_start];TreeNode root = new TreeNode(root_val);int i_root_index = map.get(root_val);int leftNum = i_root_index - i_start;root.left = buildTreeHelper(preorder, p_start + 1, p_start + leftNum + 1, inorder, i_start, i_root_index, map);root.right = buildTreeHelper(preorder, p_start + leftNum + 1, p_end, inorder, i_root_index + 1, i_end, map);return root;
}
2. 迭代 栈
用一个栈保存已经遍历过的节点,遍历前序遍历的数组,一直作为当前根节点的左子树,直到当前节点和中序遍历的数组的节点相等了,那么我们正序遍历中序遍历的数组,倒着遍历已经遍历过的根节点(用栈的 pop 实现),找到最后一次相等的位置,把它作为该节点的右子树。
代码细节
- 用一个栈保存已经遍历的节点
- 用 curRoot 保存当前正在遍历的节点
时间复杂度:O(N) 空间复杂度:O(N)
public TreeNode buildTree(int[] preorder, int[] inorder) {if (preorder.length == 0) {return null;}Stack<TreeNode> roots = new Stack<TreeNode>();int pre = 0;int in = 0;//先序遍历第一个值作为根节点TreeNode curRoot = new TreeNode(preorder[pre]);TreeNode root = curRoot;roots.push(curRoot);pre++;//遍历前序遍历的数组while (pre < preorder.length) {//出现了当前节点的值和中序遍历数组的值相等,寻找是谁的右子树if (curRoot.val == inorder[in]) {//每次进行出栈,实现倒着遍历while (!roots.isEmpty() && roots.peek().val == inorder[in]) {curRoot = roots.peek();roots.pop();in++;}//设为当前的右孩子curRoot.right = new TreeNode(preorder[pre]);//更新 curRootcurRoot = curRoot.right;roots.push(curRoot);pre++;} else {//否则的话就一直作为左子树curRoot.left = new TreeNode(preorder[pre]);curRoot = curRoot.left;roots.push(curRoot);pre++;}}return root;
}
class Solution {public TreeNode buildTree(int[] preorder, int[] inorder) {if(preorder.length==0 || inorder.length==0) {return null;}//根据前序数组的第一个元素,就可以确定根节点TreeNode root = new TreeNode(preorder[0]);for(int i=0;i<preorder.length;++i) {//用preorder[0]去中序数组中查找对应的元素if(preorder[0]==inorder[i]) {//将前序数组分成左右两半,再将中序数组分成左右两半//之后递归的处理前序数组的左边部分和中序数组的左边部分//递归处理前序数组右边部分和中序数组右边部分int[] pre_left = Arrays.copyOfRange(preorder,1,i+1);int[] pre_right = Arrays.copyOfRange(preorder,i+1,preorder.length);int[] in_left = Arrays.copyOfRange(inorder,0,i);int[] in_right = Arrays.copyOfRange(inorder,i+1,inorder.length);root.left = buildTree(pre_left,in_left);root.right = buildTree(pre_right,in_right);break;}}return root;}
}作者:wang_ni_ma
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solution/dong-hua-yan-shi-105-cong-qian-xu-yu-zhong-xu-bian/
【总结】
1.前中后序遍历变化的是[中]的位置,左到右的顺序不改变
- 前序遍历 中左右
- 中序遍历 左中右
- 后续遍历 左右中
2.还原二叉树 借助HashMap or copyOfRange
根据前序和后序遍历构造二叉树
[Leetcode][第889题][JAVA][根据前序和后序遍历构造二叉树][分治][递归]
前序+中序遍历可画出原二叉树
[Leedcode][JAVA][第105题][从前序与中序遍历序列构造二叉树][栈][递归][二叉树]
后续+中序遍历可画出原二叉树
[Leetcode][第106题][JAVA][ 从中序与后序遍历序列构造二叉树][分治][递归]
3. 多画图 写写写 遍历代码 手撕变量 大脑保持清醒
转载链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/solution/xiang-xi-tong-su-de-si-lu-fen-xi-duo-jie-fa-by–22/