LeetCode108. 将有序数组转换为二叉搜索树

108. 将有序数组转换为二叉搜索树

一、题目

给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。

高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。

示例 1:

img

输入:nums = [-10,-3,0,5,9]
输出:[0,-3,9,-10,null,5]
解释:[0,-10,5,null,-3,null,9] 也将被视为正确答案:

示例 2:

img

输入:nums = [1,3]
输出:[3,1]
解释:[1,null,3] 和 [3,1] 都是高度平衡二叉搜索树。

提示:

  • 1 <= nums.length <= 104
  • -104 <= nums[i] <= 104
  • nums严格递增 顺序排列
二、题解
方法一:递归

我们知道平衡二叉搜索树的特点是每个节点的左子树和右子树的高度差不超过1,因此我们尽可能要让节点两端的元素个数相近。

算法思路:

  1. 首先,我们要找到一个合适的根节点。由于给定的数组是有序的,我们可以选择中间位置的元素作为根节点,这样可以保证左右子树的元素数量相差不大,从而有助于维持平衡性质。

  2. 在选择了根节点之后,我们将数组分成两部分:左子数组和右子数组。左子数组中的元素都小于根节点,右子数组中的元素都大于根节点。

  3. 然后,我们递归地对左子数组和右子数组进行相同的操作,分别构建左子树和右子树。这样就能保证左右子树的高度差不超过1。

  4. 最后,将根节点与构建好的左右子树连接起来,形成一棵完整的平衡二叉搜索树。

具体实现:

class Solution {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        if(nums.size() == 0) return nullptr; // 空数组直接返回空指针(终止条件)
        int size = nums.size();
        int middle = size/2; // 找到中间位置的索引
        TreeNode *root = new TreeNode(nums[middle]); // 创建根节点
        vector<int> vecL(nums.begin(),nums.begin()+middle); // 左子数组
        vector<int> vecR(nums.begin()+middle+1, nums.end()); // 右子数组
        root->left = sortedArrayToBST(vecL); // 递归构建左子树
        root->right = sortedArrayToBST(vecR); // 递归构建右子树
        return root; // 返回根节点
    }
};

算法分析:

  • 时间复杂度:每个元素都会被遍历一次,因此总的时间复杂度为 O(n),其中 n 是数组中的元素数量。
  • 空间复杂度:每次递归都会创建新的左右子数组,因此递归的最大深度是 log(n),每层需要的空间为 O(n),所以总的空间复杂度为 O(nlogn)。
方法二:迭代

以下是代码的思路:

  1. 首先,检查给定的有序数组是否为空,如果为空,则直接返回空指针,表示空树。

  2. 创建一个根节点 root,暂时将其值设为0,作为占位值。然后创建三个队列:nodeQue 用于存储待处理的节点,leftQue 用于存储每个节点对应的左区间下标,rightQue 用于存储每个节点对应的右区间下标。

  3. 将根节点 root、左区间下标0和右区间下标 nums.size() - 1 分别入队列。

  4. 进入迭代循环,从队列中取出一个待处理的节点 curNode,同时获取它对应的左区间下标 left 和右区间下标 right,计算当前区间的中间位置 mid

  5. 将中间位置 mid 对应的元素值赋给当前节点 curNode->val,此时树的结构仍未构建。

  6. 如果左区间 left 小于等于 mid - 1,则创建左子节点,并将其入队列。更新 leftQuerightQue 分别为 leftmid - 1

  7. 如果右区间 right 大于等于 mid + 1,则创建右子节点,并将其入队列。更新 leftQuemid + 1,并维持 rightQue 不变。

  8. 重复以上步骤,直到队列为空,此时所有的节点都已经处理完毕,构建的二叉搜索树也完成。

  9. 返回根节点 root,即完成了整个构建过程。

class Solution {
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        if (nums.empty()) {
            return nullptr;
        }

        TreeNode* root = new TreeNode(0);   // 初始根节点,暂时使用0作为占位值
        queue<TreeNode*> nodeQue;           // 存储待处理的节点
        queue<int> leftQue;                 // 存储当前节点对应的左区间下标
        queue<int> rightQue;                // 存储当前节点对应的右区间下标
        nodeQue.push(root);                 // 根节点入队列
        leftQue.push(0);                    // 0为初始左区间下标
        rightQue.push(nums.size() - 1);     // nums.size() - 1为初始右区间下标

        while (!nodeQue.empty()) {
            TreeNode* curNode = nodeQue.front(); nodeQue.pop();// 当前待处理节点
            int left = leftQue.front(); leftQue.pop();    // 当前节点对应的左区间下标
            int right = rightQue.front(); rightQue.pop(); // 当前节点对应的右区间下标
            int mid = left + (right - left) / 2;  // 计算当前区间的中间位置

            curNode->val = nums[mid];   // 将中间位置元素赋值给当前节点,此时树的结构仍未构建

            if (left <= mid - 1) {  // 如果左区间仍有元素可用,创建左子节点
                curNode->left = new TreeNode(0);  
                nodeQue.push(curNode->left);  // 将左子节点加入待处理队列
                leftQue.push(left);   // 更新左区间下标
                rightQue.push(mid - 1); // 更新右区间下标
            }

            if (right >= mid + 1) { // 如果右区间仍有元素可用,创建右子节点
                curNode->right = new TreeNode(0); 
                nodeQue.push(curNode->right); // 将右子节点加入待处理队列
                leftQue.push(mid + 1); // 更新左区间下标
                rightQue.push(right);  // 更新右区间下标
            }
        }
        return root; 
    }
};

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

KeepCoding♪Toby♪

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值