从前序与中序遍历序列构造二叉树
题目描述
根据一棵树的前序遍历与中序遍历构造二叉树。
注意:
你可以假设树中没有重复的元素。
例如,给出
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:
3
/ \
9 20
/ \
15 7
解答
思路一:递归
/**
* Definition for a binary tree node.
* class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
Map<Integer, Integer> map = new HashMap<>();
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder == null || preorder.length == 0 || inorder == null || inorder.length == 0)
return null;
for (int i = 0; i < inorder.length; ++i) {
map.put(inorder[i], i);
}
return buildTree(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
}
public TreeNode buildTree(int[] preorder, int pre_start, int pre_end, int[] inorder, int in_start, int in_end) {
// 递归终止条件
if (pre_start > pre_end || in_start > in_end) return null;
TreeNode root = new TreeNode(preorder[pre_start]);
int L = map.get(preorder[pre_start]) - in_start; // 先序序列长度
// 递归生成左孩子和右孩子
root.left = buildTree(preorder, pre_start + 1, pre_start + L, inorder, in_start, in_start + L - 1);
root.right = buildTree(preorder, pre_start + L + 1, pre_end, inorder, in_start + L + 1, in_end);
return root;
}
}
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)
思路二:非递归
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
// 处理边界条件
if (preorder == null || preorder.length == 0 ||
inorder == null || inorder.length == 0) {
return null;
}
// 保存每个结点在中序遍历中的下标
Map<Integer, Integer> map = new HashMap<>();
for (int i = 0; i < inorder.length; i++) {
map.put(inorder[i], i);
}
// 初始化栈,添加根结点
Stack<TreeNode> stack = new Stack<>();
int value = preorder[0];
TreeNode root = new TreeNode(value);
stack.push(root);
// 根据先序遍历序列中的结点构建二叉树
for (int i = 1; i < preorder.length; i++) {
// 创建结点
value = preorder[i];
TreeNode node = new TreeNode(value);
if (map.get(value) < map.get(stack.peek().val)) {
// 如果当前结点在中序遍历中的下标比前一个结点小
// 根据先序遍历的特性,那么它一定是前一个结点的左孩子
stack.peek().left = node;
} else {
// 如果当前结点在中序遍历中的下标比前一个结点大,此时有两种情形:
// 1. 是前一个结点的右孩子
// 2. 是前一个结点的某个祖先的右孩子
// 出栈找到当前结点的双亲结点
TreeNode parent = null;
while (!stack.isEmpty() && map.get(value) > map.get(stack.peek().val)) {
parent = stack.pop();
}
parent.right = node;
}
stack.push(node);
}
return root;
}
}
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)
另一种非递归思路:
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
if (preorder == null || preorder.length == 0 ||
inorder == null || inorder.length == 0) {
return null;
}
Stack<TreeNode> stack = new Stack<>();
TreeNode root = new TreeNode(preorder[0]);
TreeNode cur = root;
for (int i = 1, j = 0; i < preorder.length; i++) {
// 先到最左结点
if (cur.val != inorder[j]) {
cur.left = new TreeNode(preorder[i]);
stack.push(cur);
cur = cur.left;
} else {
j++;
while (!stack.empty() && stack.peek().val == inorder[j]) {
// 遇到不相等的inorder[j]就是右孩子
cur = stack.pop();
j++;
}
cur.right = new TreeNode(preorder[i]);
cur = cur.right;
}
}
return root;
}
}
时间复杂度: O ( n ) O(n) O(n)
空间复杂度: O ( n ) O(n) O(n)