问题描述
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1
示例:
给定有序数组: [-10,-3,0,5,9],
一个可能的答案是:[0,-3,9,-10,null,5],它可以表示下面这个高度平衡二叉搜索树:
0
/ \
-3 9
/ /
-10 5
思路
先理解几个概念:
平衡二叉树:是一种二叉排序树,其中每一个节点的左子树和右子树的高度差至多等于1.
二叉搜索树:(二叉排序树)又称二叉查找树,它或者是一棵空树,或者具有一下性质的二叉树
- 若它的左子树不空,则左子树上的所有节点的值均小于它的根节点的值
- 若它的右子树不空,则右子树上的所有节点的值均大于它根节点的值
- 它的左右子树也分别为二叉排序树
当对一棵二叉搜索数进行中序遍历的时候,就可以得到一个有序的序列,这样的数称为二叉排序或搜索树
构造一棵二叉排序或搜索树的目的,并不是为了排序,而是为了提高查找和插入删除关键字的速度。
从概念中可以理解出:有序序列的中间值即为根节点,左右两边数组各自成二叉搜索树,递归是最简单的实现方式
实现
/**
1. Definition for a binary tree node.
2. public class TreeNode {
3. int val;
4. TreeNode left;
5. TreeNode right;
6. TreeNode(int x) { val = x; }
7. }
*/
class Solution {
public TreeNode sortedArrayToBST(int[] nums) {
if (nums == null || nums.length == 0) {
return null;
}
return creatSub(nums, 0, nums.length-1);
}
private static TreeNode creatSub(int[] nums,int start,int end){
int len = nums.length;
if (start > end) {
return null;
}
int rootnum = (start + end) / 2;
TreeNode root = new TreeNode(nums[rootnum]);//注意是中间是数组的值,不是排序位置
root.left = creatSub(nums, start, rootnum-1);//递归,要传入变量值
root.right = creatSub(nums, rootnum + 1, end);
return root;
}
}
犯错
- 在递归时候思路还停留在循环中,思路不清晰;
- 边界值处理不好,第一次传入从0开始到长度-1结束,若不-1,则越界;
- 创建根节点时候,要传入的 是中间数组的值,不是位置;
- 递归要传入变量,不能是具体的值;
- 每次递归调用子方法的时候,要把中间值根节点的值去掉,故rootnum-1,rootnum+1
实现2(不推荐)
从思路中我们知道,每次把中间根节点抛开,左右两边各自数组再递归调用函数即可,但这其中要复制数组,占用空间较多,比较慢,
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode(int x) { val = x; }
* }
*/
class Solution {
public TreeNode sortedArrayToBST(int[] nums){
if (nums == null || nums.length == 0) {
return null;
}
int len = nums.length;
TreeNode root = new TreeNode(nums[len / 2]);
int[] leftnum = new int[len / 2];
int[] rightnum =new int[len - len / 2 - 1];
System.arraycopy(nums,0,leftnum,0,len/2);
System.arraycopy(nums,len/2+1,rightnum,0,len - len / 2 - 1);
root.left = sortedArrayToBST(leftnum);
root.right = sortedArrayToBST(rightnum);
return root;
}
}
这里copy数组时候用了native方法,可以比赋值数组快一些
小结
本问题考察的就是二分查找,每次取中间值,再对各自边数组递归,但不一样的是,取的中间值,是中间数组的值,记住这点即可。