题目
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
代码实现
分治算法
/**
* 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 {
TreeNode head;
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder.length == 0){
return head;
}
head = new TreeNode(preorder[0]);
helper(head,preorder,inorder,0,-1,inorder.length);
return head;
}
/**
* 找到当前节点的前序位置和中序位置,
* 前序序列中: 前序位置的下一个为它的左节点,前序位置加上(当前节点位置在中序的位置inPosition-左边界left,即左子树的数量)+1为它的右节点
* 如果当前节点没有左节点,
* @param node
* @param preorder
* @param inorder
* @param prePosition 当前节点在前序序列的位置
* @param left 中序的左边界 左开右开
* @param right 中序的右边界
* @return
*/
public void helper(TreeNode node,int[] preorder, int[] inorder,int prePosition,int left,int right){
//找到当前节点在中序遍历中的位置
int inPosition = left;
for (int i = left + 1; i < right; i++) {
if (inorder[i] == preorder[prePosition]){
inPosition = i;
break;
}
}
//当前节点中序位置不是左边界+1,才有左孩子
if(inPosition != left + 1) {
//当前节点的左节点位置为前序位置+1
int leftIndex = prePosition + 1;
node.left = new TreeNode(preorder[leftIndex]);
//将当前节点在中序遍历中的位置作为左子树的右边界
helper(node.left, preorder, inorder, leftIndex, left, inPosition);
}
//当前节点中序位置不是右边界-1,才有右孩子
if (inPosition != right -1){
//当前节点的右节点位置为前序位置+左子树的数量
int rightIndex = prePosition + (inPosition - left);
node.right = new TreeNode(preorder[rightIndex]);
//将当前节点在中序遍历中的位置作为右子树的左边界
helper(node.right,preorder,inorder,rightIndex,inPosition,right);
}
}
}
分治算法2
K神代码:利用hashmap避免了使用for循环找到中序遍历对应点的高时间复杂度
class Solution {
int[] preorder;
HashMap<Integer, Integer> dic = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
this.preorder = preorder;
for(int i = 0; i < inorder.length; i++)
dic.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 = dic.get(preorder[root]); // 划分根节点、左子树、右子树
node.left = recur(root + 1, left, i - 1); // 开启左子树递归
node.right = recur(root + i - left + 1, i + 1, right); // 开启右子树递归
return node; // 回溯返回根节点
}
}