05 August 2008
Return the root node of a binary search tree that matches the given
traversal.1
preorder
(Recall that a binary search tree is a binary tree where for every node, any descendant of
has a value 1
node.left
1
<
, and any descendant of 1
node.val
has a value 1
node.right
1
>
. Also recall that a preorder traversal displays the value of the 1
node.val
first, then traverses 1
node
, then traverses 1
node.left
.)1
node.right
It’s guaranteed that for the given test cases there is always possible to find a binary search tree with the given requirements.
Example 1:
1
2
3
Input: [8,5,1,7,10,12]
Output: [8,5,10,1,7,null,12]
Constraints:
1
1 <= preorder.length <= 100
1
1 <= preorder[i] <= 10^8
1
preorder
are distinct.给一个数组,是一个BST的先序遍历,构建返回对应的BST。
1) 方法1,类似105题-Construct Binary Tree from Preorder and Inorder Traversal的做法:在105题中,需要一个先序数组和一个中序数组,由于BST的中序遍历是递增的,可以根据先序遍历排序得到一个中序遍历的数组,随后使用分治的方法从先序遍历和中序遍历构造出二叉搜索树。
具体的方法是,先获取先序遍历中的第一个元素,它对应了二叉树的根节点,它在中序遍历中的位置为 x,那么中序遍历中 x 左边的所有元素都在根节点的左子树中,x右边的所有元素都在根节点的右子树中,这样根节点的左子树和右子树中的节点个数就都确定了。再回到先序遍历数组中,由于根节点的左子树和右子树在先序遍历中一定都是连续的一段,并且它们的个数已经确定,且左子树的先序遍历出现在右子树之前,那么就得到了根节点左子树和右子树对应的先序遍历。有了子树的先序遍历和中序遍历,就可以递归地构造子树了。过程如下图:
时间复杂度:对先序数组要排序O(NlogN);
空间复杂度:额外维护一个中序遍历数组,O(N);
2) 方法2,在方法1中在将先序遍历的数组排序得到中序遍历时,花费了O(NlogN)时间复杂度,但却没有得到任何额外的信息。也就是说,可以直接跳过生成中序遍历的步骤,根据先序遍历直接构造出二叉树。需要注意的是,由于题目中的二叉树是BST,因此根据先序遍历构造出的二叉树才是唯一的。
具体做法就是使用递归的方法,在扫描先序遍历数组的同时,构造出二叉树。递归时维护一个 (lower, upper)二元组,表示当前位置可以插入的节点的值的上下界。如果此时先序遍历位置的值处于上下界中,就将这个值作为新的节点插入到当前位置,并递归地处理当前位置的左右孩子的两个位置。否则回溯到当前位置的父节点。
时间复杂度:O(N),仅扫描前序遍历一次。
空间复杂度:O(N),用来存储二叉树。
3) 方法3,方法2中的递归过程用stack来模拟
使用 for 循环迭代先序遍历中剩下的所有元素:
时间复杂度:O(N),仅扫描前序遍历一次。
空间复杂度:O(N),用来存储栈和二叉树。
方法1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
// 从前序数组的第一个元素开始
int preorderIndex = 0;
int[] preorderArr;
HashMap<Integer, Integer> indexMap = new HashMap<>();
public TreeNode bstFromPreorder(int[] preorder) {
this.preorderArr = preorder;
// 得到排序后的中序遍历数组
int[] inorderArr = Arrays.copyOf(preorder, preorder.length);
Arrays.sort(inorderArr);
// build a hashmap value -> its index
int idx = 0;
for (Integer val : inorderArr) {
indexMap.put(val, idx++);
}
// 类似105题,使用中序数组递归构建二叉树(BST)
return helper(0, inorderArr.length);
}
public TreeNode helper(int in_left, int in_right) {
// if there is no elements to construct subtrees
if (in_left == in_right)
return null;
// 先序遍历的第一个元素是根节点
int root_val = preorderArr[preorderIndex];
TreeNode root = new TreeNode(root_val);
// root splits inorder list
// into left and right subtrees
int index = indexMap.get(root_val);
// recursion
preorderIndex++;
// build left subtree
root.left = helper(in_left, index);
// build right subtree
root.right = helper(index + 1, in_right);
return root;
}
}
方法2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
class Solution {
int idx = 0;
int[] preorderArr;
int len;
public TreeNode bstFromPreorder(int[] preorder) {
this.preorderArr = preorder;
len = preorder.length;
return helper(Integer.MIN_VALUE, Integer.MAX_VALUE);
}
public TreeNode helper(int lower, int upper) {
// 如果所有先序遍历数组中的元素都用过了,说明BST已经构建完成
if (idx == len) {
return null;
}
// 得到当前元素
int val = preorderArr[idx];
// corner case,按照BST的特性,如果当前元素不能够被放在当前位置
if (val < lower || val > upper) {
return null;
}
// 构建当前元素
idx++;
TreeNode root = new TreeNode(val);
并递归构建左右子树
root.left = helper(lower, val);
root.right = helper(val, upper);
return root;
}
}
方法3
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class Solution {
public TreeNode bstFromPreorder(int[] preorder) {
int len = preorder.length;
if (len == 0) {
return null;
}
TreeNode root = new TreeNode(preorder[0]);
Deque<TreeNode> deque = new ArrayDeque<>();
deque.push(root);
for (int i = 1; i < len; i++) {
// take the last element of the deque as a parent
// and create a child from the next preorder element
TreeNode node = deque.peek();
TreeNode child = new TreeNode(preorder[i]);
// adjust the parent
while (!deque.isEmpty() && deque.peek().val < child.val)
node = deque.pop();
// follow BST logic to create a parent-child link
if (node.val < child.val) node.right = child;
else node.left = child;
// add the child into deque
deque.push(child);
}
return root;
}
}