cpp
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right)
* : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
// 从整个数组开始构造平衡二叉搜索树
// 初始区间:[0, nums.size() - 1]
return function(nums, 0, nums.size() - 1);
}
// function 的作用:
// 把 nums[left ~ right] 这一段有序数组
// 转换成一棵平衡二叉搜索树
// 最后返回这棵树的根节点
TreeNode* function(vector<int>& nums, int left, int right) {
// 1. 递归终止条件
// left > right 说明当前区间已经没有元素了
// 所以这里没有节点,返回 nullptr
if (left > right) {
return nullptr;
}
// 2. 找到当前区间的中间位置
// 因为数组是升序的,所以选择中间元素作为根节点
// 可以让左右两边的节点数量尽可能接近,从而保证树平衡
int mid = (left + right) / 2;
// 3. 用中间元素创建当前根节点
TreeNode* root = new TreeNode(nums[mid]);
// 4. 把左半部分交给递归
// nums[left ~ mid-1] 中的元素都比 nums[mid] 小
// 所以构造出来的树作为 root 的左子树
root->left = function(nums, left, mid - 1);
// 5. 把右半部分交给递归
// nums[mid+1 ~ right] 中的元素都比 nums[mid] 大
// 所以构造出来的树作为 root 的右子树
root->right = function(nums, mid + 1, right);
// 6. 当前这一层的树已经构造完成
// 把当前根节点返回给上一层递归
return root;
}
};
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode() : val(0), left(nullptr), right(nullptr) {}
* TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
* TreeNode(int x, TreeNode *left, TreeNode *right)
* : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
TreeNode* sortedArrayToBST(vector<int>& nums) {
// 从整个数组开始构造平衡二叉搜索树
// 初始区间:[0, nums.size() - 1]
return function(nums, 0, nums.size() - 1);
}
// function 的作用:
// 把 nums[left ~ right] 这一段有序数组
// 转换成一棵平衡二叉搜索树
// 最后返回这棵树的根节点
TreeNode* function(vector<int>& nums, int left, int right) {
// 1. 递归终止条件
// left > right 说明当前区间已经没有元素了
// 所以这里没有节点,返回 nullptr
if (left > right) {
return nullptr;
}
// 2. 找到当前区间的中间位置
// 因为数组是升序的,所以选择中间元素作为根节点
// 可以让左右两边的节点数量尽可能接近,从而保证树平衡
int mid = (left + right) / 2;
// 3. 用中间元素创建当前根节点
TreeNode* root = new TreeNode(nums[mid]);
// 4. 把左半部分交给递归
// nums[left ~ mid-1] 中的元素都比 nums[mid] 小
// 所以构造出来的树作为 root 的左子树
root->left = function(nums, left, mid - 1);
// 5. 把右半部分交给递归
// nums[mid+1 ~ right] 中的元素都比 nums[mid] 大
// 所以构造出来的树作为 root 的右子树
root->right = function(nums, mid + 1, right);
// 6. 当前这一层的树已经构造完成
// 把当前根节点返回给上一层递归
return root;
}
};
整体思路
这道题的核心就是:
每次取有序数组的中间元素作为根节点,然后左半部分递归构造左子树,右半部分递归构造右子树。
比如:
nums = [1, 2, 3, 4, 5]
第一次:
left = 0
right = 4
mid = 2
nums[mid] = 3
所以先创建:
3
/ \
? ?
然后:
root->left = function(nums, 0, 1);
把:
[1, 2]
交给递归构造左子树。
再:
root->right = function(nums, 3, 4);
把:
[4, 5]
交给递归构造右子树。
最终可能得到:
3
/ \
1 4
\ \
2 5
它满足:
左子树 < 根 < 右子树
所以是 BST,同时左右节点数量比较接近,因此是高度平衡的。
这道题的递归框架
你可以重点记成:
// 1. 终止条件
if (left > right) {
return nullptr;
}
// 2. 当前层做什么
int mid = (left + right) / 2;
TreeNode* root = new TreeNode(nums[mid]);
// 3. 子问题交给递归
root->left = function(nums, left, mid - 1);
root->right = function(nums, mid + 1, right);
// 4. 返回当前结果给上一层
return root;
一句话总结:
取中间当根,左边递归建左子树,右边递归建右子树,最后返回当前根节点。
这题也非常符合你前面总结的递归思想:我只负责当前的 mid 节点,左右部分相信递归能够帮我处理好。