题目描述:
输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
示例:
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
思路:
前序遍历特点:节点按照 [根节点 | 左子树 | 右子树]
排序,以题目示例为例:[3 | 9 | 20 15 7]
中序遍历特点:节点按照 [左子树 | 根节点 | 右子树]
排序,以题目示例为例:[9 | 3 | 15 20 7]
- 在二叉树的前序遍历序列中,第一个数字总是树的根节点的值。
- 在中序遍历序列中,根节点的值在序列的中间,左子树的节点的值在根节点的值的左边,右子树的值在根节点的右边。为了快速的找到中序遍历序列中根节点的值,可以建立一个Map,以值为Map的键,以索引为Map的值。
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
Map<Integer, Integer> map = new HashMap<>();
int[] po;
public TreeNode buildTree(int[] preorder, int[] inorder) {
po = preorder;
for (int i = 0; i < inorder.length; ++i) {
map.put(inorder[i], i);
}
return recur(0, preorder.length - 1, 0, inorder.length-1);
}
/**
preLeft: 递归求子树时在前序遍历序列中的开始位置
preRight: 递归求子树时在前序遍历序列中的结束位置
inLeft: 递归求子树时在中序遍历序列中的开始位置
inRifht: 递归求子树时在中序遍历序列中的开始位置
indexMap: 中序遍历序列键值对Map
*/
private TreeNode recur(int preLeft, int preRight, int inLeft, int inRight) {
if (preLeft > preRight) {
return null;
}
//根节点在前序遍历中的索引就是preLeft
int rootVal = po[preLeft];
TreeNode root = new TreeNode(rootVal);
if (preLeft == preRight) {
return root;
} else {
//根节点在中序遍历中的索引
int rootInIndex = map.get(rootVal);
//在当前根节点下左子树的节点个数,用中序遍历根节点索引减去中序遍历的头
//在当前根节点下右子树的节点个数,用中序遍历的尾减去根节点索引
int leftNums = rootInIndex - inLeft, rightNums = inRight - rootInIndex;
//左子树遍历
root.left = recur(preLeft + 1, preLeft + leftNums, inLeft, rootInIndex - 1);
//右子树遍历
root.right = recur(preLeft + leftNums + 1, preRight, rootInIndex + 1, inRight);
return root;
}
}
}