给定一个二叉树的中序与后序遍历结果,请你根据两个序列构造符合这两个序列的二叉树。
数据范围:二叉树的节点数满足
,节点上的值满足
,保证节点的值各不相同
例如输入[2,1,4,3,5],[2,4,5,3,1]时,
根据中序遍历的结果[2,1,4,3,5]和后序遍历的结果[2,4,5,3,1]可构造出二叉树{1,2,3,#,#,4,5},如下图所示:
[1],[1]
{1}
[2,1,4,3,5],[2,4,5,3,1]
{1,2,3,#,#,4,5}
import java.util.*;
/*
* public class TreeNode {
* int val = 0;
* TreeNode left = null;
* TreeNode right = null;
* public TreeNode(int val) {
* this.val = val;
* }
* }
*/
/**
* NC223 从中序与后序遍历序列构造二叉树
* @author d3y1
*/
public class Solution {
HashMap<Integer,Integer> inMap = new HashMap<>();
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
* 相似 -> NC12 重建二叉树 [nowcoder]
*
* @param inorder int整型一维数组 中序遍历序列
* @param postorder int整型一维数组 后序遍历序列
* @return TreeNode类
*/
public TreeNode buildTree (int[] inorder, int[] postorder) {
// return solution1(inorder, postorder);
// return solution2(inorder, postorder);
// return solution22(inorder, postorder);
return solution3(inorder, postorder);
}
/**
* 递归
* @param inorder
* @param postorder
* @return
*/
private TreeNode solution1(int[] inorder, int[] postorder){
return construct(inorder, postorder);
}
/**
* 递归
* @param inorder
* @param postorder
* @return
*/
public TreeNode construct(int[] inorder, int[] postorder){
int n = postorder.length;
if(n == 0){
return null;
}
// 当前根结点
int rootVal = postorder[n-1];
TreeNode root = new TreeNode(rootVal);
// 当前根结点 左子树节点个数
int left = 0;
while(inorder[left] != rootVal){
left++;
}
if(left > 0){
root.left = construct(Arrays.copyOfRange(inorder, 0, left), Arrays.copyOfRange(postorder, 0, left));
}
// 当前根结点 右子树节点个数
int right = n-(left+1);
if(right > 0){
root.right = construct(Arrays.copyOfRange(inorder, left+1, n), Arrays.copyOfRange(postorder, left, n-1));
}
return root;
}
//////////////////////////////////////////////////////////////////////////////////////
/**
* 哈希 + 递归
* @param inorder
* @param postorder
* @return
*/
private TreeNode solution2(int[] inorder, int[] postorder){
int n = inorder.length;
if(n == 0){
return null;
}
// 哈希: val -> idx
for(int i=0; i<n; i++){
inMap.put(inorder[i], i);
}
// 根结点
TreeNode root = new TreeNode(postorder[n-1]);
// 递归遍历
dfs(postorder, root, 0, n-1, 0, n-1);
return root;
}
/**
* 递归遍历
* @param postorder
* @param root
* @param inLeft
* @param inRight
* @param postLeft
* @param postRight
*/
private void dfs(int[] postorder, TreeNode root, int inLeft, int inRight, int postLeft, int postRight){
int inRootIdx = inMap.get(root.val);
int leftSize = inRootIdx-inLeft;
int rightSize = inRight-inRootIdx;
// 有左子树
if(leftSize > 0){
root.left = new TreeNode(postorder[postLeft+leftSize-1]);
dfs(postorder, root.left, inLeft, inRootIdx-1, postLeft, postLeft+leftSize-1);
}
// 有右子树
if(rightSize > 0){
root.right = new TreeNode(postorder[postRight-1]);
dfs(postorder, root.right, inRootIdx+1, inRight, postLeft+leftSize, postRight-1);
}
}
//////////////////////////////////////////////////////////////////////////////////////
/**
* 哈希+递归: 简化
* @param inorder
* @param postorder
* @return
*/
private TreeNode solution22(int[] inorder, int[] postorder){
int n = inorder.length;
if(n == 0){
return null;
}
// 哈希: val -> idx
for(int i=0; i<n; i++){
inMap.put(inorder[i], i);
}
// 递归遍历
return dfs(postorder, 0, n-1, 0, n-1);
}
/**
* 递归遍历: 简化
* @param postorder
* @param inLeft
* @param inRight
* @param postLeft
* @param postRight
*/
private TreeNode dfs(int[] postorder, int inLeft, int inRight, int postLeft, int postRight){
TreeNode root = new TreeNode(postorder[postRight]);
int inRootIdx = inMap.get(root.val);
int leftSize = inRootIdx-inLeft;
int rightSize = inRight-inRootIdx;
// 有左子树
if(leftSize > 0){
root.left = dfs(postorder, inLeft, inRootIdx-1, postLeft, postLeft+leftSize-1);
}
// 有右子树
if(rightSize > 0){
root.right = dfs(postorder, inRootIdx+1, inRight, postLeft+leftSize, postRight-1);
}
return root;
}
//////////////////////////////////////////////////////////////////////////////////////
// 后序遍历根结点索引
private int postRootIdx;
private TreeNode solution3(int[] inorder, int[] postorder){
int n = postorder.length;
postRootIdx = n-1;
// 哈希: val -> idx
for(int i=0; i<n; i++){
inMap.put(inorder[i], i);
}
return build(postorder, 0, n-1);
}
/**
* 递归遍历
*
* 二叉树后序遍历: 左 -> 右 -> 根
* 可利用该性质直接找到后序遍历根节点, 子树遍历先右后左: (根) -> 右 -> 左
*
* @param postorder
* @param inLeft
* @param inRight
* @return
*/
private TreeNode build(int[] postorder, int inLeft, int inRight){
if(inLeft > inRight){
return null;
}
// 根
int postRootVal = postorder[postRootIdx--];
TreeNode root = new TreeNode(postRootVal);
if(inLeft == inRight){
return root;
}
// 中序遍历根结点索引
int inRootIdx = inMap.get(postRootVal);
// 右
root.right = build(postorder, inRootIdx+1, inRight);
// 左
root.left = build(postorder, inLeft, inRootIdx-1);
return root;
}
} int[] post;
HashMap<Integer,Integer> inorderMap = new HashMap<Integer,Integer>();
public TreeNode buildTree (int[] inorder, int[] postorder) {
for(int i = 0;i<inorder.length;i++){
inorderMap.put(inorder[i],i);
}
// write code here
post = postorder;
int len = inorder.length;
return build(0,len - 1,0,len -1);
}
private TreeNode build(int inleft,int inright,int postleft,int postright){
if(inleft > inright || postleft > postright){
return null;
}
int value = post[postright];
int index = inorderMap.get(value);
TreeNode root = new TreeNode(value);
root.left = build(inleft,index - 1,postleft,postleft+index-inleft -1);
root.right = build(index+1,inright,postleft+index-inleft,postright -1);
return root;
} 思路:
1.中序遍历顺序:左根右;后序遍历顺序:左右根;根据给出的后序遍历数组可知,数组末元素为根结点值;取出该结点,作为根结点的值。
2.根据中序遍历顺序,找出根结点位置rootIdx;在中序遍历数组中,该结点左边元素为左子树结点值,右边为右子树结点值;在后序遍历数组中,可知从0到rootIdx为左子树结点,从rootIdx到倒数第二个元素为右子数结点。
3.根据中序遍历左子数,后序遍历左子数数组初始化左子树,作为根结点的左子树;根据中序遍历右子数,后序遍历右子数数组初始化右子树,作为根结点的右子树;
4.返回根结点
public class Solution {
public TreeNode buildTree (int[] inorder, int[] postorder) {
for (int i = 0; i < inorder.length; i++)
map.put(inorder[i], i);
return help(inorder, 0, inorder.length-1, postorder, 0, postorder.length-1);
}
public Map<Integer, Integer> map = new HashMap<>();
public TreeNode help(int[] inorder, int inStart, int inEnd,
int[] postorder, int postStart, int postEnd) {
if (inStart > inEnd) return null;
int idx = map.get(postorder[postEnd]);
int l = idx - inStart;
TreeNode root = new TreeNode(postorder[postEnd]);
root.left = help(inorder, inStart, idx-1,
postorder, postStart, postStart+l-1);
root.right = help(inorder, idx+1, inEnd,
postorder, postStart+l, postEnd-1);
return root;
}
} import java.util.*;
/*
* public class TreeNode {
* int val = 0;
* TreeNode left = null;
* TreeNode right = null;
* public TreeNode(int val) {
* this.val = val;
* }
* }
*/
public class Solution {
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param inorder int整型一维数组 中序遍历序列
* @param postorder int整型一维数组 后序遍历序列
* @return TreeNode类
*/
public TreeNode buildTree (int[] inorder, int[] postorder) {
// write code here
if(inorder.length != postorder.length || inorder == null || inorder.length == 0) return null;
int rootVal = postorder[postorder.length - 1]; // 后序遍历的最后一个元素是根节点
TreeNode tree = new TreeNode(rootVal); // 构建根节点
// 找到根节点在中序遍历中的位置
int rootIndex = 0;
for(int i = 0; i < inorder.length; i++){
if(inorder[i] == rootVal){
rootIndex = i;
break;
}
}
// 将序列划分为左右两个子树部分,分别进行重构
tree.left = buildTree(Arrays.copyOfRange(inorder, 0, rootIndex), Arrays.copyOfRange(postorder, 0, rootIndex));
tree.right = buildTree(Arrays.copyOfRange(inorder, rootIndex + 1, inorder.length), Arrays.copyOfRange(postorder, rootIndex, postorder.length - 1));
return tree;
}
}