106.从中序与后序遍历序列构造二叉树
一、题目描述
给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。
例如,给出
中序遍历 inorder = [9,3,15,20,7] 后序遍历 postorder = [9,15,7,20,3] 返回如下的二叉树:
提示:
- 1 <= inorder.length <= 3000
- postorder.length == inorder.length
- -3000 <= inorder[i], postorder[i] <= 3000
- inorder 和 postorder 都由 不同 的值组成
- postorder 中每一个值都在 inorder 中
- inorder 保证是树的中序遍历
- postorder 保证是树的后序遍历
二、解题思路
如何根据两个顺序构造一个唯一的二叉树?
答:以 后序数组的最后一个元素为切割点,先切中序数组,根据中序数组,反过来在切后序数组。一层一层切下去,每次后序数组最后一个元素就是节点元素。
流程如图:
递归法
那么代码应该怎么写呢?
说到一层一层切割,就应该想到了递归。
一共分为六步:
- 第一步:如果数组大小为零的话,说明是空节点了。
- 第二步:如果不为空,那么取后序数组最后一个元素作为节点元素。
- 第三步:找到后序数组最后一个元素在中序数组的位置,作为切割点
- 第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
- 第五步:切割后序数组,切成后序左数组和后序右数组
- 第六步:递归处理左区间和右区间
三、AC代码
递归法
class Solution {
Map<Integer, Integer> map;
public TreeNode buildTree(int[] inorder, int[] postorder) {
map = new HashMap<>();
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i], i);
}
return findNode(inorder, 0, inorder.length, postorder, 0 , postorder.length);
}
TreeNode findNode(int[] inorder, int inBegin, int inEnd,
int[] postorder, int postBegin, int postEnd) {
if (inBegin >= inEnd || postBegin >= postEnd) {
return null;
}
int rootIndex = map.get(postorder[postEnd-1]);
TreeNode root = new TreeNode(inorder[rootIndex]);
int lenLeft = rootIndex - inBegin;
root.left = findNode(inorder, inBegin, inBegin+lenLeft,
postorder, postBegin, postBegin+lenLeft);
root.right = findNode(inorder, rootIndex+1, inEnd,
postorder, postBegin+lenLeft, postEnd-1);
return root;
}
}
105.从前序与中序遍历序列构造二叉树
一、题目描述
给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。
例如,给出
前序遍历 preorder = [3,9,20,15,7] 中序遍历 inorder = [9,3,15,20,7] 返回如下的二叉树:
提示:
- 1 <= inorder.length <= 3000
- postorder.length == inorder.length
- -3000 <= inorder[i], postorder[i] <= 3000
- inorder 和 postorder 都由 不同 的值组成
- postorder 中每一个值都在 inorder 中
- inorder 保证是树的中序遍历
- postorder 保证是树的后序遍历
二、解题思路
跟 106.从中序与后序遍历序列构造二叉树 相比,区别在后序遍历序列换成前序遍历序列,一样的道理。
递归法
一共分为六步:
- 第一步:如果数组大小为零的话,说明是空节点了。
- 第二步:如果不为空,那么取前序数组第一个元素作为节点元素。
- 第三步:找到前序数组第一个元素在中序数组的位置,作为切割点
- 第四步:切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组)
- 第五步:切割前序数组,切成前序左数组和前序右数组
- 第六步:递归处理左区间和右区间
三、AC代码
递归法
class Solution {
Map<Integer, Integer> map;
public TreeNode buildTree(int[] preorder, int[] inorder) {
map = new HashMap<>();
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i], i);
}
return findNode(inorder, 0, inorder.length, preorder, 0 , preorder.length);
}
TreeNode findNode(int[] inorder, int inBegin, int inEnd,
int[] preorder, int preBegin, int preEnd) {
if (inBegin >= inEnd || preBegin >= preEnd) {
return null;
}
int rootIndex = map.get(preorder[preBegin]);
TreeNode root = new TreeNode(inorder[rootIndex]);
int lenLeft = rootIndex - inBegin;
root.left = findNode(inorder, inBegin, inBegin+lenLeft,
preorder, preBegin+1, preBegin+1+lenLeft);
root.right = findNode(inorder, rootIndex+1, inEnd,
preorder, preBegin+1+lenLeft, preEnd);
return root;
}
}
参考代码随想录:https://programmercarl.com/