一、思路和算法
为了构建BST,应该在数组中选取一个数nums[i]
用来构建根节点,nums[0, i - 1]
用来构建左子树,nums[i + 1, n - 1]
用来构建右子树。
为了让二叉树尽量平衡,很自然的想法就是让根节点尽量在数组的中间,让数组左右两边的长度尽量相等。
基于以上的直觉,当数组长度为2k + 1
时,根节点选在数组正中间,左右两棵子树都分配k
个节点。当数组长度为2k
时,根节点选在数组中间靠左的位置,左子树分配k - 1
个节点,右子树分配k
个节点。
二、证明
很显然,上面的算法构建的是二叉查找树,对于任意一个节点,左子树的值都小于根节点的值,右子树的值都大于根节点的值。
现在我们利用数学归纳法证明上面给出的算法构建的是平衡树:
当数组长度<= 2
时,很容易验证构造的是平衡树。
假设数组长度< k
时构造的是平衡树,那么可以证明数组长度= k
时构造的也是平衡树。
记左子树为l
,右子树为r
;左子树的左右子树分别为ll
,lr
;右子树的左右子树分别为 rl
,rr
。树tree
的节点个数我们用|tree|
来表示,高度用h(tree)
来表示。
1)|l| < k
,|r| < k
,根据假设可知l和r均为平衡树。
2)若k
为奇数,那么|l| == |r|
,构造算法也相同,所以l和r是两棵结构完全相同的树,所以当前构造的二叉树为平衡树。
3)若k为偶数,那么|l| + 1 = |r|
。记|l| = x
,那么|r| = x + 1
。
当x
为奇数时,有|ll| = |lr| = |rl| = y, |rr| = y + 1
。所以0 <= h(rr) - h(rl)
,又由于r
为平衡树,所以h(rr) - h(rl) <= 1
。
h(l) = h(ll) + 1 = h(rl) + 1,h(r) = h(rr) + 1
,所以有0 <= h(r) - h(l) <= 1
,所以当前构造的是平衡树。
当x
为偶数时,通过类似的分析,同样能推出当前构造的是平衡树。
三、完整代码
class Solution {
private int[] nums;
public TreeNode sortedArrayToBST(int[] nums) {
this.nums = nums;
return sArray2BST(0, nums.length - 1);
}
private TreeNode sArray2BST(int left, int right) {
if (left > right) return null;
if (left == right) return new TreeNode(nums[left]);
int mid = left + (right - left) / 2;
TreeNode root = new TreeNode(nums[mid]);
root.left = sArray2BST(left, mid - 1);
root.right = sArray2BST(mid + 1, right);
return root;
}
}