
本文介绍如何将升序数组直接构造成符合完全二叉树索引约定(左子节点在 2i+1,右子节点在 2i+2)且满足BST性质的数组形式,避免构建TreeNode对象,提升效率。
本文介绍如何将升序数组直接构造成符合完全二叉树索引约定(左子节点在 2i+1,右子节点在 2i+2)且满足bst性质的数组形式,避免构建treenode对象,提升效率。
在常规的「有序数组转BST」问题中,我们通常采用取中位数为根、递归构造左右子树的方式,生成一棵高度平衡的BST——但该方法产出的是逻辑结构(TreeNode链表),其内存布局不满足数组下标与父子关系的线性映射规则(即 left[i] = 2i+1, right[i] = 2i+2)。
而本题目标并非任意BST,而是以完全二叉树形态存储的BST:即用一维数组 tree[] 表示树,其中索引 i 处元素的左、右子节点严格位于 2i+1 和 2i+2,父节点位于 Math.floor((i-1)/2)。此时,若要同时满足BST性质(左子树所有值 中序遍历结果等于原升序数组。
? 关键洞察:
完全二叉树的中序遍历访问顺序,恰好对应其数组索引按“左-根-右”递归展开的自然顺序。因此,我们只需按中序遍历的路径(即先递归左子树 → 填当前索引 → 递归右子树),依次将升序数组中的元素“注入”到目标数组对应位置即可。
以下是高效实现(无需新建节点,直接生成目标数组):
function sortedArrayToCompleteBST(nums) {
// 确保输入有序(若已排序可跳过)
nums.sort((a, b) => a - b);
const iterator = nums.values(); // 创建迭代器,保证按序取值
const tree = new Array(nums.length); // 预分配结果数组
function inorderFill(index) {
// 超出数组长度,终止递归
if (index >= nums.length) return;
// 1. 递归填充左子树(对应索引 2*index + 1)
inorderFill(2 * index + 1);
// 2. 当前位置填入下一个有序值(中序访问点)
tree[index] = iterator.next().value;
// 3. 递归填充右子树(对应索引 2*index + 2)
inorderFill(2 * index + 2);
}
inorderFill(0); // 从根节点索引 0 开始
return tree;
}
// 示例调用
const nums = [4, 7, 8, 10, 11, 12, 16, 20, 24, 28];
const result = sortedArrayToCompleteBST(nums);
console.log(result); // [16, 10, 24, 7, 12, 20, 28, 4, 8, 11]
✅ 输出验证(以 result[0] === 16 为例):
-
result[0] = 16(根) - 左子节点
result[1] = 10,右子节点result[2] = 24→ 满足10 -
result[1] = 10的左子节点为result[3] = 7,右子节点为result[4] = 12→7 - 同理可验证其余节点均满足BST性质,且索引关系严格遵循完全二叉树定义。
⚠️ 注意事项:
- 输入必须严格升序(或经
sort()排序),否则中序注入将破坏BST性质; - 输出数组长度固定为
nums.length,空位用undefined占位(本实现预分配,无空位); - 时间复杂度
O(n),空间复杂度O(n)(含递归栈深度,最坏O(log n)); - 此方案生成的是最小高度完全BST(因完全二叉树本身高度最优),兼顾平衡性与紧凑存储。
该方法跳过对象构造开销,直击本质——利用中序遍历与BST/完全二叉树的双重结构性质,实现简洁、高效、可预测的数组化BST构建。










