题目

题目来源:力扣(LeetCode)

给你一棵二叉搜索树,请你返回一棵 平衡后 的二叉搜索树,新生成的树应该与原来的树有着相同的节点值。

如果一棵二叉搜索树中,每个节点的两棵子树高度差不超过 1 ,我们就称这棵二叉搜索树是 平衡的 。

如果有多种构造方法,请你返回任意一种。

示例:
image.pngimage.png

输入:root = [1,null,2,null,3,null,4,null,null]
输出:[2,1,3,null,null,null,4]
解释:这不是唯一的正确答案,[3,1,4,null,2,null,null] 也是一个可行的构造方案。

思路分析

AVL 树是一棵二叉搜索树,它具备自平衡的能力,它的左右子树都是 AVL 树,且左右子树的高度差的绝对值不超过1。

本题可用 AVL 树求解,但并不是最优解。

我们可以利用二叉搜索树的性质,中序遍历把二叉树转变为有序数组,然后取有序数组中间的元素作为根节点递归构造平衡二叉搜索树。

对于区间 [L, R]:

  • 取 mid= ( L + R) / 2 ,即中心位置作为当前节点的值;
  • 如果 L ≤ mid - 1,那么递归地将区间 [L, mid−1] 作为当前节点的左子树;
  • 如果mid + 1 ≤ R,那么递归地将区间 [mid + 1, R] 作为当前节点的右子树。
  1. /**
  2. * Definition for a binary tree node.
  3. * function TreeNode(val, left, right) {
  4. * this.val = (val===undefined ? 0 : val)
  5. * this.left = (left===undefined ? null : left)
  6. * this.right = (right===undefined ? null : right)
  7. * }
  8. */
  9. /**
  10. * @param {TreeNode} root
  11. * @return {TreeNode}
  12. */
  13. var balanceBST = function (root) {
  14. // 存储中序遍历后得到的有序序列
  15. const trees = []
  16. // 中序遍历获取有序序列
  17. inorder(root)
  18. // 二分法递归构建平衡二叉搜索树
  19. return buildTree(trees)
  20. // 中序遍历构造有序序列
  21. function inorder(root) {
  22. if (root === null) return
  23. inorder(root.left)
  24. trees.push(root.val)
  25. inorder(root.right)
  26. }
  27. // 根据有序序列构建平衡二叉搜索树
  28. function buildTree(arr) {
  29. if (arr.length === 0) return null
  30. // 二分法获取中间节点作为平衡二叉搜索树的根节点
  31. const mid = arr.length >> 1
  32. const root = new TreeNode(arr[mid])
  33. // 递归构造左子树
  34. root.left = buildTree(arr.slice(0, mid))
  35. // 递归构造右子树
  36. root.right = buildTree(arr.slice(mid + 1))
  37. return root
  38. }
  39. }