将有序数组转换为二叉搜索树
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵平衡二叉搜索树。
1.递归法:
解题步骤:
为了使得得到的树是平衡二叉搜索树,取数组nums
的中位数为根节点,以中位数为分割点切分左右子树,这样能保证做右子树的高度差达到最小化;
左右子树重复前面的操作:取中位数为根节点,以中位数为分割点切分左右子树;
当下标left > right
时递归调用结束,也意味着数组中没有节点供我们使用了。
注意事项:
一定要保持从始至终下标要么是左闭右闭区间,要么就是左闭右开。我这里选择左闭右闭。
中位数如何取?
可以直接取两下标的平均:middle = (left + right) / 2
对于奇数个下标的数组:可以直接求出中间下标;
对于偶数个下标的数组:middle不是中间下标,而是中间位置左边的数字下标,这不会影响后续结果。
小优化:
避免栈溢出的风险,可以将middle = (left + right) / 2
优化成middle = (right - left) / 2 + left
,或者middle = (right - left) >> 1 + left
最终代码如下:
TreeNode* BuildBST(vector<int>& nums, int left, int right)
{
if(left > right) return nullptr;
// 定义中间位置作为根节点
int middle = ((right - left) >> 1) + left;
TreeNode* newnode = new TreeNode(nums[middle]);
// 中间节点分割左右区间
newnode->left = BuildBST(nums, left, middle - 1);
newnode->right = BuildBST(nums, middle + 1, right);
return newnode;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
return BuildBST(nums, 0, nums.size() - 1);
}
复杂度分析
时间复杂度: O(N),其中 N 是数组的长度。每个数字都要访问一次。
空间复杂度: O(logN),其中 N 是数组的长度。空间复杂度取决于递归栈的深度,递归栈的深度是 O(logN),也就是整个二叉树的高度。
2.迭代法:
建立三个队列:
qNode队列用于存放遍历的节点,节点的初始化交给另外两个队列完成;
qLeft队列用于存放区间的左边界下标;
qRight队列用于存放区间的右边界下标;
当取出左右边界下标,即可计算出middle,也就能初始化qNode里的节点了。
TreeNode* sortedArrayToBST(vector<int>& nums) {
if(nums.size() == 0) return nullptr;
// qNode用于存放遍历的节点
TreeNode* root = new TreeNode(0);
queue<TreeNode*> qNode; qNode.push(root);
// qLeft用于存放左边界下标
queue<int> qLeft; qLeft.push(0);
// qRight用于存放右边界下标
queue<int> qRight; qRight.push(nums.size() - 1);
while(!qNode.empty())
{
TreeNode* root = qNode.front(); qNode.pop();
int left = qLeft.front(); qLeft.pop();
int right = qRight.front(); qRight.pop();
// 得到中节点下标
int middle = ((right - left) >> 1) + left;
root->val = nums[middle]; // 将根节点的值改为中间节点的值
// 划分左区间
if(left <= middle - 1)
{
root->left = new TreeNode(0); // 创建新节点连接在root->left
qNode.push(root->left);
qLeft.push(left);
qRight.push(middle - 1);
}
// 划分右区间
if(middle + 1 <= right)
{
root->right = new TreeNode(0); // 创建新节点连接在root->right
qNode.push(root->right);
qLeft.push(middle + 1);
qRight.push(right);
}
}
return root;
}