一、题目
二、思路
- 每一次递归都可以把一棵大树拆分为左右子树和根元素,符合递归的问题细分原则,使用递归解决;
- 递归时每一层递归工作就是单一的生成当前结点,赋值后连接至上一层递归,每一层都会递归处理该节点的左右子树,直到当前节点为null,见解法一;
- 优化方法,每层递归都需要做一次for循环获取当前根在中序遍历中的下标,可以通过一个HashMap提前保存中序遍历中的所有值及其下标,每次获取时只需要get一下就行,见解法一(优化);
三、解法
解法一
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
// 初始时
int preB = 0;
int preE = preorder.length;
int inB = 0;
int inE = inorder.length;
return recursion(preorder, preB, preE, inorder, inB, inE);
}
private TreeNode recursion(
int[] preorder, int preB, int preE,
int[] inorder, int inB, int inE) {
// 1. 划定终止条件: 已经遍历到叶节点的子结点(null)了
if (preB == preE) {
return null; // 返回上一层
}
// 2. 生成结点并插入树中对应位置
int curRoot = preorder[preB]; // 先序: 根左右
TreeNode node = new TreeNode(curRoot);
// 3. 计算新左右子树的起止下标
// 新左子树: 中序遍历中根结点的左方
// pre - (3) [9] 20 15 7
// in - [9] (3) 15 20 7
// 下标:
// 先序: (先序起点 + 1) ---> (先序起点 + 1 + 左子树长度)
// 中序: (中序起点) ---> (中序根位置)
int inRootPos = 0;
for (int i = inB; i < inE; i++) {
if (curRoot == inorder[i]) {
inRootPos = i;
break;
}
}
// 左子树长度求法:
// - [9] (3) [15 20 7]
// - 中序遍历根左边的部分
int leftLen = inRootPos - inB;
node.left = recursion(
preorder, preB + 1, preB + 1 + leftLen,
inorder, inB, inRootPos);
// 新右子树: 中序遍历中根结点的右方
// pre - (3) 9 [20 15 7]
// in - 9 (3) [15 20 7]
// 下标:
// 先序: (先序起点 + 1 + 左子树长度) ---> (先序终点)
// 中序: (中序根位置 + 1) ---> (中序终点)
node.right = recursion(
preorder, preB + 1 + leftLen, preE,
inorder, inRootPos + 1, inE);
return node;
}
}
解法一(优化)
class Solution {
private final HashMap<Integer, Integer> map = new HashMap();
public TreeNode buildTree(int[] preorder, int[] inorder) {
int preB = 0;
int preE = preorder.length;
int inB = 0;
int inE = inorder.length;
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i], i);
}
return recursion(preorder, preB, preE, inorder, inB, inE);
}
private TreeNode recursion(
int[] preorder, int preB, int preE,
int[] inorder, int inB, int inE) {
if (preB == preE) {
return null;
}
int curRoot = preorder[preB];
TreeNode node = new TreeNode(curRoot);
int inRootPos = map.get(curRoot);
int leftLen = inRootPos - inB;
node.left = recursion(
preorder, preB + 1, preB + 1 + leftLen,
inorder, inB, inRootPos);
node.right = recursion(
preorder, preB + 1 + leftLen, preE,
inorder, inRootPos + 1, inE);
return node;
}
}