输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如,给出:
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
以下是用递归写出的方法,使用了时间换空间的做法,因为无法动态加载数组。
package Mypage;
public class Solution {
public static void main(String[] args) {
int[] pd = {3,4,9,7,6,5,8};
int[] id = {9,4,7,3,5,6,8};
Solution solution = new Solution();
TreeNode tree = solution.buildTree(pd, id);
print_tree(tree);
}
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder.length==0){
return null;
}
int root = preorder[0];//根节点
int left_len = 0;//左子树个数
int right_len = 0;//右子树个数
for(int i = 0;i<inorder.length;i++){//循环遍历中序数组,找到左子树和右子树
if(inorder[i]==root){//若遍历到根节点,则记录左子树的节点个数
left_len = i;
right_len = inorder.length-i-1;
}
}
int[] pd_left = new int[left_len];//左子树前序
int[] id_left = new int[left_len];//左子树中序
int[] pd_right = new int[right_len];//右子树前序
int[] id_right = new int[right_len];//右子树中序
// System.out.println("=========前序============");
for(int i = 1,j=0,k=0;i<preorder.length;i++){
if(i<=left_len){
pd_left[j++] = preorder[i];
// System.out.println(preorder[i]);
}else{
pd_right[k++] = preorder[i];
// System.out.println(preorder[i]);
}
}
// System.out.println("=========中序============");
for(int i = 0,j=0,k=0;i<inorder.length;i++){
if(i<left_len){
id_left[j++] = inorder[i];
// System.out.println(inorder[i]);
}else if((left_len)==i){
continue;
}else{
id_right[k++] = inorder[i];
// System.out.println(inorder[i]);
}
}
Solution solution = new Solution();
TreeNode rootNode = new TreeNode(root);
//先递归左子树
if(left_len!=0){//如果左子树不为空,则需要递归,递归返回的是左子树
TreeNode leftNode = solution.buildTree(pd_left, id_left);//返回本节点的左子树
//将左子树添加在根节点上
rootNode.left = leftNode;
}
if(right_len!=0){//如果右子树不为空,则需要递归,递归返回的是右子树
TreeNode rightNode = solution.buildTree(pd_right, id_right);//返回本节点的右子树
//将左子树添加在根节点上
rootNode.right = rightNode;
}
return rootNode;
}
public static void print_tree(TreeNode treeNode) {
System.out.println(treeNode.val);
if(treeNode.left != null){
print_tree(treeNode.left);
}
if(treeNode.right != null){
print_tree(treeNode.right);
}
}
}
思路解读:
- 按照前序的特点,数组中的第一个数必定是根节点。
- 按照中序特点,数组中根节点的左边必定是左子树,右边必定是右子树。、
- 可以根据递归的方法遍历每个节点。
代码解读:
- 判断数组是否为空,为空则返回null。(第一次提交,就遇到这个坑,往后需要注意)
- 遍历循环前序和中序,记录左子树和右子树的节点个数。
- 根据节点个数创建数组,获取到左子树前序中序和右子树前序中序。
- 创建当前节点,将当前节点的值传入。(当前节点的值就是前序第一个值)
- 开始递归,先递归左子树,将左子树返回值添加到当前节点的左子树上。之后递归右子树。
- 最后返回本节点。