力扣-树-重构二叉树
1.从前序与中序遍历序列构造二叉树(LeetCode 105)
- 题目概述:给定一棵树的前序遍历 preorder 与中序遍历 inorder。请构造二叉树并返回其根节点。(假设并无重复元素)
- 题目案例:
- 解题思路:根据前序遍历找到根节点,然后将中序遍历划分为左右子树,然后左右子树进行同样的操作,即递归。这里有一个小细节就是用一个hashmap存放中序遍历的结点序号,方便查找(注意是以无重复元素为前提),这里直接放官方代码
- 注意:划分左右子树时不要搞混与root的关系
class Solution {
private Map<Integer,Integer> indexMap;
public TreeNode buildTree(int[] preorder, int[] inorder) {
int n = preorder.length;
// 构造哈希映射,帮助我们快速定位根节点
indexMap = new HashMap<Integer, Integer>();
for (int i = 0; i < n; i++) {
indexMap.put(inorder[i], i);
}
return myBuildTree(preorder, inorder, 0, n - 1, 0, n - 1);
}
public TreeNode myBuildTree(int[] preorder,int[] inorder,int preorder_left,int preorder_right,int inorder_left,int inorder_right){
if (preorder_left > preorder_right) {
return null;
}
// 前序遍历中的第一个节点就是根节点
int preorder_root = preorder_left;
// 在中序遍历中定位根节点
int inorder_root = indexMap.get(preorder[preorder_root]);
// 先把根节点建立出来
TreeNode root = new TreeNode(preorder[preorder_root]);
// 得到左子树中的节点数目
int size_left_subtree = inorder_root - inorder_left;
// 递归地构造左子树,并连接到根节点
// 先序遍历中「从 左边界+1 开始的 size_left_subtree」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
root.left = myBuildTree(preorder, inorder, preorder_left + 1, preorder_left + size_left_subtree, inorder_left, inorder_root - 1);
// 递归地构造右子树,并连接到根节点
// 先序遍历中「从 左边界+1+左子树节点数目 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
root.right = myBuildTree(preorder, inorder, preorder_left + size_left_subtree + 1, preorder_right, inorder_root + 1, inorder_right);
return root;
}
}
- java升级代码(与106解法同,解释可根据下面的106)
public class Solution {
int[] preorder;
int[] inorder;
int pre_index;
Map<Integer, Integer> idx_map = new HashMap<Integer, Integer>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
this.preorder=preorder;
this.inorder = inorder;
pre_index=0;
int idx=0;
for(Integer val:inorder){
idx_map.put(val,idx++);
}
return myBuild(0,inorder.length-1);
}
public TreeNode myBuild(int in_left,int in_right){
if(in_left>in_right) return null;
int root_val = preorder[pre_index];
TreeNode root = new TreeNode(root_val);
int index = idx_map.get(root_val);
pre_index++;
root.left = myBuild(in_left, index - 1);
root.right = myBuild(index + 1, in_right);
return root;
}
}
2.从中序与后序遍历序列构造二叉树(LeetCode 106)
-
题目概述:根据一棵树的中序遍历与后序遍历构造二叉树。(假设并无重复元素)
-
题目案例:
-
解题思路:这题与105基本类似,通过后序遍历找到根节点的位置上,在根据中序遍历划分左右子树
-
注意:这里最开始我用了和第一种一样的方法,显示超时(还不知道是什么原因,可能使个人原因),所以放了官方代码,与105相比做了一些升级。
106的解法并未把后序遍历的数组及其左右边界编号作为参数传入,而是将数组作为全局变量,仅将每次分隔的index作为全局变量运用在方法中,这里很巧妙的把index放在全局变量中,这样递归时index的值就会改变,这里还要注意一定是先右后左,这样index- -才会正确,因为后序遍历的顺序是左右后,这样会简单很多。
class Solution {
int post_idx;
int[] postorder;
int[] inorder;
Map<Integer, Integer> idx_map = new HashMap<Integer, Integer>();
public TreeNode helper(int in_left, int in_right) {
// 如果这里没有节点构造二叉树了,就结束
if (in_left > in_right) {
return null;
}
// 选择 post_idx 位置的元素作为当前子树根节点
int root_val = postorder[post_idx];
TreeNode root = new TreeNode(root_val);
// 根据 root 所在位置分成左右两棵子树
int index = idx_map.get(root_val);
// 下标减一
post_idx--;
// 构造右子树
root.right = helper(index + 1, in_right);
// 构造左子树
root.left = helper(in_left, index - 1);
return root;
}
public TreeNode buildTree(int[] inorder, int[] postorder) {
this.postorder = postorder;
this.inorder = inorder;
// 从后序遍历的最后一个元素开始
post_idx = postorder.length - 1;
// 建立(元素,下标)键值对的哈希表
int idx = 0;
for (Integer val : inorder) {
idx_map.put(val, idx++);
}
return helper(0, inorder.length - 1);
}
}