题目描述: 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
- 首先想到的就是一边建立二叉排序树一边对树进行调整成为二叉平衡树,一般手动建树就是这种方法,建立二叉排序树就是选中第一个结点作为根结点,之后吧比它小的结点插入它的左子树,比它大的结点插入右子树,插入过程也按照二叉排序树的规则,左子树的结点都小于根节点,右子树的结点都大于根节点。调整成二叉平衡树的过程也分为LL、RR、LR、RL旋转。
//JS
var sortedArrayToBST = function(nums) {
class AVLNode {
constructor(){
this.root = null;
}
//插入结点
insert(val){
const insertNode = (node, val) => {
if(!node) return new TreeNode(val);
if(node.val == val) return node;
//插入左子树
if(node.val > val) {
node.left = insertNode(node.left, val);
//找到自己要插入的位置后,调整为AVL树
if(this.getDepth(node.left) - this.getDepth(node.right) > 1) {
if(val < node.left.val) node = this.rotateLeft(node);
else node = this.rotateLeftRight(node);
}
}
//插入右子树
else {
node.right = insertNode(node.right, val);
if(this.getDepth(node.right) - this.getDepth(node.left) > 1) {
if(val > node.right.val) node = this.rotateRight(node);
else node = this.rotateRightLeft(node);
}
}
return node;
}
//每次插入结点之后都调整一遍成平衡树,所以再次插入结点时还是要从根结点开始比较找到自己要插入的位置
this.root = insertNode(this.root, val);
}
//计算子树高度
getDepth(node){
if(!node) return 0;
return Math.max(this.getDepth(node.left), this.getDepth(node.right)) + 1;
}
//LL 右单旋转
rotateLeft(node){
const newNode = node.left;
node.left = newNode.right;
newNode.right = node;
return newNode;
}
//RR 右单旋转
rotateRight(node){
const newNode = node.right;
node.right = newNode.left;
newNode.left = node;
return newNode;
}
//LR 先左后右旋转
rotateLeftRight(node){
//先左
node.left = this.rotateRight(node.left);
//后右
return this.rotateLeft(node);
}
//RL 先右后左旋转
rotateRightLeft(node){
//先右
node.right = this.rotateLeft(node.right);
//后左
return this.rotateRight(node);
}
}
let tree = new AVLNode();
for(let num of nums)
tree.insert(num);
return tree.root;
};
- 但既然这是一道简单题,肯定就是有简单题的解法的。二叉排序树按照其中序遍历就是一个有序的序列,如果每次都选择中间结点作为子树的根结点就可以保证其平衡。奇数个结点时,可选择中间结点,偶数个结点可以选择两个中间结点中的任意一个结点作为根结点。
//JS
var sortedArrayToBST = function(nums) {
//从奇数个结点的中间结点或者偶数个结点的左侧中间结点开始
let dfs = (left, right) => {
if(left > right) return null;
let mid = Math.floor((left + right) / 2);
let root = new TreeNode(nums[mid]);
root.left = dfs(left, mid - 1);
root.right = dfs(mid + 1, right);
return root;
};
return dfs(0, nums.length - 1);
};
var sortedArrayToBST = function(nums) {
//从偶数个结点的右侧中间结点开始
let dfs = (left, right) => {
if(left > right) return null;
let mid = Math.floor((left + right) / 2);
if((left + right) % 2)
mid += 1; //加1
let root = new TreeNode(nums[mid]);
root.left = dfs(left, mid - 1);
root.right = dfs(mid + 1, right);
return root;
};
return dfs(0, nums.length - 1);
};
var sortedArrayToBST = function(nums) {
//从偶数个结点的左侧或者右侧中间结点开始
let dfs = (left, right) => {
if(left > right) return null;
let mid = Math.floor((left + right) / 2);
if((left + right) % 2)
mid += Math.floor(Math.random() * 2); //随机加1
let root = new TreeNode(nums[mid]);
root.left = dfs(left, mid - 1);
root.right = dfs(mid + 1, right);
return root;
};
return dfs(0, nums.length - 1);
};