Leetcode105. 从前序与中序遍历序列构造二叉树
题目描述
/**
* 给定一棵树的前序遍历 preorder 与中序遍历 inorder。
* <p>
* 请构造二叉树并返回其根节点。
*/
思路分析
- 已知前序遍历和中序遍历的数组,构造其二叉树
- 根据前序遍历和中序遍历的特点可知,前序遍历在遍历二叉树时先遍历根节点,随后遍历左子树,最后遍历右子树,中序遍历在遍历二叉树时先遍历左子树,随后遍历根节点,最后遍历右子树
- 可知前序遍历时始终先遍历根节点,因此前序遍历的第一个节点就是二叉树的根节点
- 由中序遍历的特点可知根节点始终位于最中间,对中序遍历的数组进行hash映射,键为节点值,值为对中序遍历数组的索引,因此可以根据键很快找到其位置
- 确立树的根节点后,使用递归的思路,构造左子树和右子树,即将中序遍历数组从根节点一分为二进行构造
- 源码及详解见下
源码及分析
private Map<Integer, Integer> map;
/**
*
* @param preorder 前序遍历数组
* @param inorder 中序遍历数组
* @return
*/
public TreeNode buildTree(int[] preorder, int[] inorder) {
int n = inorder.length;
//构造哈希映射,快速定位根节点
map = new HashMap<>();
for (int i = 0; i < n; i++) {
map.put(inorder[i], i);
}
return myBuildTree(preorder, inorder, 0, n - 1, 0, n - 1);
}
/**
*
* @param preorder 前序遍历数组
* @param inorder 中序遍历数组
* @param preorder_left 前序遍历左侧节点索引
* @param preorder_right 前序遍历右侧节点索引
* @param inorder_left 中序遍历左侧节点索引
* @param inorder_right 中序遍历右侧节点索引
* @return
*/
public TreeNode myBuildTree(int[] preorder, int[] inorder, int preorder_left, int preorder_right, int inorder_left, int inorder_right) {
//递归结束条件
if (preorder_left > preorder_right) {
return null;
}
//前序遍历的第一个节点就是根节点
int preorder_root = preorder_left;
//在中序遍历中定位根节点
int inorder_root = map.get(preorder[preorder_root]);
//先把根节点建立出来
TreeNode root = new TreeNode(preorder[preorder_root]);
//得到左子树中的节点数目
int size_left_subtree = inorder_root - inorder_left;
//递归的构造左子树,并连接到根节点
root.left = myBuildTree(preorder, inorder, preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1);
//递归的构造右子树,并连接到根节点
root.right = myBuildTree(preorder, inorder, preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right);
return root;
}