剑指 Offer 07. 重建二叉树
使用列表+递归实现,虽然时间复杂度比较高,因为列表通过值查索引的效率不高,但是胜在好理解!加了详细的注释,方便自己日后复习,同时也希望可以帮助其他人,如有错误,欢迎指正
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
// 用两个ArrayList分别存储前序和中序遍历的数组
// 前序的列表是为了更方便地得到根节点
// 中序的列表是为了更方便地切割左右子树
List<Integer> preorder_list = new ArrayList<Integer>();
List<Integer> inorder_list = new ArrayList<Integer>();
for (int i = 0; i < preorder.length; i++){
preorder_list.add(preorder[i]);
inorder_list.add(inorder[i]);
}
// 递归,不断通过递归的方法去生成左右子树,并连接到根节点上
return recursion(preorder_list,inorder_list);
}
private TreeNode recursion(List<Integer> preorder_list,List<Integer> inorder_list){
// 递归的结束条件:当中序遍历的列表空了说明该根节点已经没有该递归方向的子树了,那么该节点在该方向的子树就是null,直接返回null即可
if (inorder_list.isEmpty()){
return null;
}
/**当前树的根节点其实就是前序遍历列表的第一个节点,我们直接先构建一下根节点;
这里要注意的是我们为了每次递归传入的都是preorder_list,再构建完该树的根节点后,需要remove列表中的这个值
注意我们能不停地使用preorder_list的第一个元素作为根节点,是因为我们前序遍历的顺序与构建整棵树的顺序是一致的(哈哈哈,我个人的理解,如果有错误请指正,感谢!)*/
TreeNode node = new TreeNode(preorder_list.remove(0));
/**有了根节点后,我们需要继续构建它的左右子树,而左右子树需要通过切割中序遍历的列表得到,中序遍历列表的根节点左边是左子树,右边是右子树; 所以我们找到根节点在中序遍历的索引,利用这个索引来切割*/
int node_index = inorder_list.indexOf(node.val);
// 把切割后的左子树和右子树分别再进行递归,知道达到递归退出的条件即可;
// 此外preorder_list这个参数我们前面说过了,每次都拿出第一个元素做根节点即可
node.left = recursion(preorder_list,inorder_list.subList(0,node_index));
// 注意subList()这个方法的右边界是不包括的,所以右边界我们这里用inorder_list.size(),而不是inorder_list.size() - 1
node.right = recursion(preorder_list,inorder_list.subList(node_index + 1,inorder_list.size()));
// 每次递归都需要返回一个根节点,给上一层的根节点作为一棵子树
return node;
}
}