Problem: 1382. 将二叉搜索树变平衡
文章目录
- [1. 整体思路](#1. 整体思路)
- [2. 完整代码](#2. 完整代码)
- [3. 时空复杂度](#3. 时空复杂度)
-
-
- [时间复杂度: O ( N ) O(N) O(N)](#时间复杂度: O ( N ) O(N) O(N))
- [空间复杂度: O ( N ) O(N) O(N)](#空间复杂度: O ( N ) O(N) O(N))
-
1. 整体思路
核心问题
我们需要将一棵可能高度不平衡 的二叉搜索树(BST),转换成一棵高度平衡的二叉搜索树。
算法逻辑
-
中序遍历 (In-order Traversal):
- 二叉搜索树的特性 :通过中序遍历(左 -> 根 -> 右)可以得到一个升序的节点值序列。
- 我们将原 BST 的所有节点值按照中序遍历的顺序存入一个
List<Integer>中。 - 这一步将树结构转化为了有序数组结构,消除了原本的树结构信息。
-
有序数组转平衡 BST (Reconstruction):
- 这是一个经典问题(LeetCode 108. 将有序数组转换为二叉搜索树)。
- 策略 :为了让生成的 BST 尽可能平衡,我们应该总是选择数组的中间元素作为根节点。
- 这样,数组被均分为左右两半,左半部分构建左子树,右半部分构建右子树。
- 这个过程递归进行,直到数组范围为空。
- 由于每次都取中点,左右子树的高度差最多为 1,从而保证了结果是一棵高度平衡的 BST。
2. 完整代码
java
import java.util.ArrayList;
import java.util.List;
/**
* Definition for a binary tree node.
* public class TreeNode {
* int val;
* TreeNode left;
* TreeNode right;
* TreeNode() {}
* TreeNode(int val) { this.val = val; }
* TreeNode(int val, TreeNode left, TreeNode right) {
* this.val = val;
* this.left = left;
* this.right = right;
* }
* }
*/
class Solution {
public TreeNode balanceBST(TreeNode root) {
// 1. 中序遍历获取升序数组
List<Integer> nums = inorderTraversal(root);
// 2. 将有序数组转换为平衡二叉搜索树
return sortedArrayToBST(nums);
}
// 中序遍历辅助方法
private List<Integer> inorderTraversal(TreeNode node) {
List<Integer> ans = new ArrayList<>();
dfs(ans, node);
return ans;
}
// DFS 实现中序遍历
private void dfs(List<Integer> ans, TreeNode node) {
if (node == null) {
return;
}
dfs(ans, node.left);
ans.add(node.val);
dfs(ans, node.right);
}
// 重建平衡 BST 入口
private TreeNode sortedArrayToBST(List<Integer> nums) {
// 这里的 range 是 [left, right) 左闭右开区间
return buildBST(nums, 0, nums.size());
}
// 递归构建平衡 BST
// left: 当前处理范围的起始索引 (inclusive)
// right: 当前处理范围的结束索引 (exclusive)
private TreeNode buildBST(List<Integer> nums, int left, int right) {
// 递归终止条件:区间为空
if (left == right) {
return null;
}
// 取中间元素作为根节点
// >>> 1 是无符号右移,相当于除以 2,但在处理负数时更安全(虽然这里索引是非负的)
int m = (left + right) >>> 1;
// 创建新节点,值为中间元素
// 递归构建左子树:范围 [left, m)
// 递归构建右子树:范围 [m + 1, right)
return new TreeNode(nums.get(m), buildBST(nums, left, m), buildBST(nums, m + 1, right));
}
}
3. 时空复杂度
假设二叉树的节点总数为 N N N。
时间复杂度: O ( N ) O(N) O(N)
- 中序遍历 :访问每个节点一次,耗时 O ( N ) O(N) O(N)。
- 重建 BST :
- 构建过程本质上也是对每个节点访问一次(每次递归创建一个新节点)。
- 总共有 N N N 个节点需要创建。
- 虽然
buildBST是递归调用的,但总的节点创建操作是线性的。 - 耗时 O ( N ) O(N) O(N)。
- 总计 : O ( N ) + O ( N ) = O ( N ) O(N) + O(N) = O(N) O(N)+O(N)=O(N)。
空间复杂度: O ( N ) O(N) O(N)
- 有序列表
nums:我们需要一个长度为 N N N 的ArrayList来存储节点值,空间 O ( N ) O(N) O(N)。 - 递归栈空间 :
- 中序遍历时,最坏情况(斜树)栈深度为 N N N。
- 重建 BST 时,树是平衡的,栈深度为 log N \log N logN。
- 取最大值,空间复杂度为 O ( N ) O(N) O(N)。
- 结论 : O ( N ) O(N) O(N)。