题目:
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
分析方法:分而治之
结合“前序遍历”和“中序遍历”的定义
前序遍历的第1个节点一定是二叉树的根节点;
中序遍历中根节点把中序遍历分成两部分,左边部分构成了二叉树的根节点的左子树,右边部分构成了二叉树根节点的右子树。
确定3为根节点,根据中序遍历,可以知道,3左边为根节点的左子树,右边为根节点的右子树;接下来进行递归...
接下来屡一下思路
假设preLeft为前序遍历的左边界,preRight为前序遍历的右边界;inLeft为中序遍历的左边界,inRight为中序遍历的右边界。
则preLeft指向的为根节点root,根节点左子树的左边界为preLeft+1,同时可以在中序遍历中找到根节点,设pIndex指向中序遍历根节点,则中序遍历中根节点左子树的区间为[inLeft,pIndex-1],右子树的区间为[pIndex+1,inRight]。剩下不知道的就是前序遍历左子树的右边界和右子树的左边界,但是其左子树长度和中序遍历长度一致,可以由如下关系获得:
最终结果如下
编写代码:
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
public static TreeNode buildTree(int[] preorder, int[] inorder) {
int preLen = preorder.length;//前序遍历的长度
int inLen = inorder.length;//中序遍历的长度
// 可以不做判断,因为题目中给出的数据都是有效的
if (preLen != inLen) {
return null;
}
// 以空间换时间,否则,找根结点在中序遍历中的位置需要遍历
Map<Integer, Integer> map = new HashMap<>(inLen);
for (int i = 0; i < inLen; i++) {
map.put(inorder[i], i);
}
return buildTree(preorder,0, preLen - 1,map, 0, inLen - 1);
}
/**
* 根据前序遍历数组的 [preL, preR] 和 中序遍历数组的 [inL, inR] 重新组建二叉树
*
*
* @param preorder
* @param preL 前序遍历数组的区间左端点
* @param preR 前序遍历数组的区间右端点
* @param map
* @param inL 中序遍历数组的区间左端点
* @param inR 中序遍历数组的区间右端点
* @return 构建的新二叉树的根结点
*/
private static TreeNode buildTree(int[] preorder, int preL, int preR,
Map<Integer, Integer> map, int inL, int inR) {
if (preL > preR || inL > inR) {
return null;
}
// 构建的新二叉树的根结点一定是前序遍历数组的第 1 个元素
int rootVal = preorder[preL];
TreeNode root = new TreeNode(rootVal);
int pIndex = map.get(rootVal );//中序遍历根节点的索引
// 按照图中描述,计算边界的取值
root.left = buildTree(preorder, preL + 1, preL + (pIndex - inL), map, inL, pIndex - 1);
root.right = buildTree(preorder, preL + (pIndex - inL) + 1, preR, map, pIndex + 1, inR);
return root;
}
至此结束!
来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。