文章参考
1. 题目描述
- preorder:前序。inorder:中序。postorder:后序。
- 输出结果就是 从上至下,从左至右,9没有孩子所以null。
2. 解题思路
- 首先知道前序遍历:根左右。中序:左根右
- 根据以上性质可以推断:
- 前序时第一个是根节点。
- 根据前序结果,在中序时候,搜索根节点可以划分左右子树。
- 根据划分的子树中节点数,可以把前序结果划分为 根 | 左子树 | 右子树
根据上面三步,可以确定3个节点:1.根节点 2.左子树根节点 3.右子树根节点
使用分治,对左右子树递归求解
分析:
递推参数:
根节点前序遍历索引(只有前序才能确定根节点) root
子树在中序遍历的范围(左边界) left (只有中序才能依据根节点划分左右子树)
子树在中序遍历的范围(右边界) right
终止条件:left > right,表示中序依据根节点划分结束了,没有左右子树了 return null
步骤:
1. 建立根节点 node:节点值 = preorder[root],前序[索引] = 根节点值
2. 划分左右子树:查找根节点在中序的索引i,i左边为左子树,i右边为右子树。
3. 使用hash建立中序遍历 值和索引的映射
4. 递归构造左右子树
注意:
-----------------------------------------------------------------------------------------------
根节点索引(前序条件下) 中序遍历左边界 中序遍历右边界
左子树 root + 1 left(默认0索引,从头开始) i - 1
(前序:根右边就是左子树,但不知长度)
右子树 root +(i-left)+ 1 i+1(i是中序根索引) right(默认最后一个索引)
(i-left)= 左子树长度,注意
不是个数,而是长度,1-3个数有3个数,
长度是2
-----------------------------------------------------------------------------------------------
重点:
1. 前序中,根+左子树长度+1 = 右子树根索引:如根=0,左子树长度1,则0+1+1=2=右子树索引
2. 前序只能知道根节点,左子树根节点,而不知道边界(即左右子树长度)
3. 中序才能获取左右子树边界条件
总结:前序找根,中序划分 !!!
- 前序找每次需要的根节点,然后依据中序划分子树的左右。
3. 代码
class Solution {
HashMap<Integer, Integer> map = new HashMap<>();
int[] preorder;
public TreeNode buildTree(int[] preorder, int[] inorder) {
this.preorder = preorder;
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i], i);
}
return recursive(0,0,inorder.length-1);
}
TreeNode recursive(int pre_root_idx, int in_left_idx, int in_right_idx){
if(in_left_idx > in_right_idx) return null;
TreeNode root = new TreeNode(preorder[pre_root_idx]);
int idx = map.get(preorder[pre_root_idx]);
root.left = recur(pre_root_idx + 1, in_left_idx, idx - 1);
root.right = recur(pre_root_idx + (idx - in_left_idx) + 1, idx+1, in_right_idx);
return root;
}
}
4. 心得体会
- 分治法
- 树形结构分左右,一般分成左右的都可以考虑分治
- 前序找根,中序划分!!!!!!!!!!
- 步骤
- 保留先序找根;创建字典。
- 备份先序;put字典;return(0,0,length-1)
- 推出条件left>right;创建节点root;中序找根索引idx;root.left=;root.right=;返回root(其实是一个node,可以看成每次都是父节点)。