将二叉搜索树变平衡
难度:
标签:
题目描述
给你一棵二叉搜索树,请你返回一棵 平衡后 的二叉搜索树,新生成的树应该与原来的树有着相同的节点值。如果有多种构造方法,请你返回任意一种。
如果一棵二叉搜索树中,每个节点的两棵子树高度差不超过 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 <= 105
代码结果
运行时间: 312 ms, 内存: 21.8 MB
/*
* 题目思路:
* 1. 使用Java Stream收集二叉搜索树的中序遍历结果。
* 2. 将中序遍历结果转为平衡二叉树。
*/
import java.util.*;
import java.util.stream.*;
public class Solution {
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int val) { this.val = val; }
}
public TreeNode balanceBST(TreeNode root) {
// 使用stream收集中序遍历结果
List<Integer> inorderList = new ArrayList<>();
inorderTraversal(root).forEach(inorderList::add);
// 构建平衡二叉树
return buildBalancedTree(inorderList, 0, inorderList.size() - 1);
}
private Stream<Integer> inorderTraversal(TreeNode node) {
if (node == null) return Stream.empty();
return Stream.concat(Stream.concat(
inorderTraversal(node.left),
Stream.of(node.val)),
inorderTraversal(node.right));
}
private TreeNode buildBalancedTree(List<Integer> nums, int left, int right) {
if (left > right) return null;
int mid = left + (right - left) / 2;
TreeNode root = new TreeNode(nums.get(mid));
root.left = buildBalancedTree(nums, left, mid - 1);
root.right = buildBalancedTree(nums, mid + 1, right);
return root;
}
}
解释
方法:
该题解的主要思路分为两个步骤:
1. 利用中序遍历将二叉搜索树转换成一个有序数组。中序遍历的顺序保证了数组的有序性,因为对于任何二叉搜索树,其中序遍历结果都是按照键值升序排列的。
2. 使用递归方法根据有序数组构建一棵平衡二叉搜索树(BST)。选取数组的中间元素作为树的根节点,然后递归地对中间元素的左半部分和右半部分执行同样的操作,分别生成左子树和右子树。这种方法可以确保新树的平衡性,因为每次都是从中间划分数组。
时间复杂度:
O(n)
空间复杂度:
O(n)
代码细节讲解
🦆
为什么在构建平衡二叉搜索树时选择数组的中间元素作为根节点,而不是其他位置的元素?
▷🦆
在将二叉搜索树转换成有序数组的过程中,如何处理树中的重复元素?是否有可能影响最终构建的平衡二叉搜索树的结构?
▷🦆
在递归构建平衡二叉搜索树的过程中,如果节点总数为偶数,选择中间元素有两种可能(中间两个元素任选一个),这会如何影响树的平衡性?
▷🦆
题解中提到,递归调用的深度最坏情况下为O(log n),但在构建过程中确实可能出现更不平衡的情况吗?如果出现,是在什么情况下?
▷