M1382.将二叉搜索树变平衡
binary search tree, divide and conquer, https://leetcode.cn/problems/balance-a-binary-search-tree/
给你一棵二叉搜索树,请你返回一棵 平衡后 的二叉搜索树,新生成的树应该与原来的树有着相同的节点值。如果有多种构造方法,请你返回任意一种。
如果一棵二叉搜索树中,每个节点的两棵子树高度差不超过 1 ,我们就称这棵二叉搜索树是 平衡的 。
示例 1:

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

输入: root = [2,1,3]
输出: [2,1,3]提示:
- 树节点的数目在
[1, 104]范围内。 1 <= Node.val <= 10^5
这道题的解题思路可以分为两个主要步骤:
- 中序遍历(In-order Traversal):由于二叉搜索树(BST)的中序遍历结果是一个有序数组,我们首先通过中序遍历将树中所有的节点值提取出来,存入一个列表。
- 分治法构建平衡 BST:有了有序数组后,为了让生成的树尽可能平衡,我们可以每次取数组的中间元素作为当前子树的根节点,然后递归地用左半部分数组构建左子树,用右半部分数组构建右子树。
代码实现
python
# Definition for a binary tree node.
# class TreeNode:
# def __init__(self, val=0, left=None, right=None):
# self.val = val
# self.left = left
# self.right = right
class Solution:
def balanceBST(self, root: TreeNode) -> TreeNode:
# 1. 中序遍历提取有序数值列表
nums = []
def inorder(node):
if not node:
return
inorder(node.left)
nums.append(node.val)
inorder(node.right)
inorder(root)
# 2. 通过有序数组构建平衡 BST(类似二分查找的过程)
def build(left, right):
if left > right:
return None
# 选择中间位置的数字作为根节点,确保左右子树节点数量差距最小
mid = (left + right) // 2
node = TreeNode(nums[mid])
# 递归构建左子树和右子树
node.left = build(left, mid - 1)
node.right = build(mid + 1, right)
return node
return build(0, len(nums) - 1)复杂度分析
时间复杂度:
- 中序遍历需要访问每个节点一次,耗时
。 - 构建平衡 BST 的过程中,每个数组元素也只会被访问一次,耗时
。 - 其中
是二叉树中的节点个数。
- 中序遍历需要访问每个节点一次,耗时
空间复杂度:
- 我们需要一个大小为
的数组 nums来存储中序遍历的结果。 - 递归调用的栈深度:中序遍历最坏情况下为
(当树退化为链表时),构建平衡树的递归深度为 。因此总空间复杂度为 。
- 我们需要一个大小为
为什么这样做是平衡的?
当我们总是选择有序数组的中间元素作为根时,左边和右边的元素个数之差最多为 1。这意味着左子树和右子树的节点总数非常接近,递归下去就能保证每一个节点的左右子树高度差不超过 1,从而符合平衡二叉树的定义。