题目8:108. 将有序数组转换为二叉搜索树
同类题目
前置知识
中序遍历:左节点 → 根节点 → 右节点。
二叉搜索树
二叉搜索树(Binary Search Tree)是指一棵空树或具有如下性质的二叉树
- 若任意节点的左子树不空,则左子树上所有节点的值均小于它的根节点的值
- 若任意节点的右子树不空,则右子树上所有节点的值均大于它的根节点的值
- 任意节点的左、右子树也分别为二叉搜索树
- 没有键值相等的节点
基于以上性质,我们可以推导出一个二叉搜索树的特性:二叉搜索树的中序遍历结果为递增序列。
题目描述
给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵
平衡
二叉搜索树。
示例 1:
输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]
解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案:
示例 2:
输入:nums = [1,3]
输出:[3,1]
解释:[1,null,3] 和 [3,1] 都是高度平衡二叉搜索树。
提示:
1 <= nums.length <= 104-104 <= nums[i] <= 104nums按 严格递增 顺序排列
思路分析
本题数组nums 是一个按照升序排序的数组,其和二叉搜索树的中序遍历一一对应。
那么从数组如何构造一棵树呢?子问题+递归的思想,树是由很多节点构建的,对于其中一个节点的构建可以分成三步
- 创建当前节点
- 构建当前节点的左子树
- 构建当前节点的右子树
其它的交给递归框架即可。
通过二叉搜索树的中序遍历,是否可以唯一地确定二叉搜索树? 以 nums = [-10,-3,0,5,9]为例
我们从排序数组中可以任意选一个节点作为根节点都可以构建出二叉搜索树,显而易见构建了多个不同的二叉树。
那么平衡树呢?
我们从排序数组选择中间节点构建平衡二叉搜索树,中间节点依赖节点总数。
总数是奇数: nums = [-10,-3,0,5,9] 中间节点为0
总数是偶数: nums = [-10,-3,0,5,9,10] 中间节点可以是0 或 5
显而易见构建了多个不同的平衡二叉搜索树。
选择好二叉搜索树的根节点之后,就依据上文讨论的子问题+递归的思想建树方法进行建树。
程序代码
//https://leetcode.cn/problems/convert-sorted-array-to-binary-search-tree/description/
// 108. 将有序数组转换为二叉搜索树
#include<iostream>
#include<vector>
using namespace std;
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 * createTree(vector<int>& nums, int l, int r)
{
// base case
if(l>r)
{
return nullptr;
}
// 选择中间节点
int mid = l + (r-l)/2;
TreeNode *cur = new TreeNode(nums[mid]);
// 递归创建左子树
cur->left = createTree(nums,l,mid-1);
// 递归创建右子树
cur->right = createTree(nums,mid+1,r);
return cur;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
TreeNode * root = createTree(nums,0,nums.size()-1);
return root;
}
};
复杂度分析
时间复杂度: O(N) 其中N为二叉树的节点数量。
空间复杂度: O(logN) 其中N为二叉树的节点数量,树的深度为logN 。
题目感悟
二叉搜索树左子树上所有节点的值均小于它的根节点的值,右子树上所有节点的值均大于它的根节点的值,其中序遍历结果为递增序列。
更多相关知识:github.com/pingguo1987…