当前位置: 首页 > news >正文

【Leetcode hot 100】108.将有序数组转换为二叉搜索树

问题链接

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

问题描述

给你一个整数数组 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 <= 10^4
  • -10^4 <= nums[i] <= 10^4
  • nums 按 严格递增 顺序排列

问题解答

本题核心是利用升序数组的特性平衡二叉搜索树(BST)的定义,通过「分治思想」构建树结构。平衡BST要求左右子树高度差不超过1,而升序数组的中间元素作为根节点时,左右子树的节点数会尽可能均匀,天然满足平衡条件。

题目基础概念

  • 平衡BST:任意节点的左右子树高度差的绝对值不超过1。
  • 升序数组与BST的关联:BST的中序遍历结果是升序序列,因此升序数组可视为BST的中序遍历结果,只需确定「根节点位置」即可反向构建树。
  • 根节点选择:数组长度为奇数时,中间元素唯一;为偶数时,选左中间(left + (right-left)/2)或右中间((left+right+1)/2)均可,不影响平衡(题目允许答案不唯一)。

递归解法(推荐)

递归是最直观的实现,符合分治思想:将数组划分为「根节点+左子数组+右子数组」,递归构建左、右子树。

1. 递归思路

  • 参数定义:传入数组nums、左边界left、右边界right(左闭右闭区间,避免重复创建子数组,提高效率)。
  • 终止条件:当left > right时,返回null(空节点)。
  • 单层逻辑
    1. 计算中间索引mid(避免(left+right)/2的整数溢出问题);
    2. nums[mid]为值创建根节点;
    3. 递归构建左子树(区间[left, mid-1]);
    4. 递归构建右子树(区间[mid+1, right]);
    5. 返回根节点。

2. 递归代码

// 二叉树节点定义(LeetCode环境中已默认提供,此处为清晰展示)
class TreeNode {int val;TreeNode left;TreeNode right;TreeNode() {}TreeNode(int val) { this.val = val; }TreeNode(int val, TreeNode left, TreeNode right) {this.val = val;this.left = left;this.right = right;}
}class Solution {public TreeNode sortedArrayToBST(int[] nums) {// 初始调用:处理整个数组(左边界0,右边界nums.length-1)return buildTree(nums, 0, nums.length - 1);}// 递归构建子树的核心方法private TreeNode buildTree(int[] nums, int left, int right) {// 终止条件:区间无效,返回空节点if (left > right) {return null;}// 计算中间索引(避免溢出:left + (right-left)/2 等价于 (left+right)/2,但无溢出)int mid = left + (right - left) / 2;// 1. 创建当前根节点(中间元素)TreeNode root = new TreeNode(nums[mid]);// 2. 递归构建左子树(左区间:[left, mid-1])root.left = buildTree(nums, left, mid - 1);// 3. 递归构建右子树(右区间:[mid+1, right])root.right = buildTree(nums, mid + 1, right);// 返回当前根节点,供父节点连接return root;}
}

3. 复杂度分析

  • 时间复杂度O(n),每个节点仅创建1次,共n个节点。
  • 空间复杂度O(log n),递归栈深度为树的高度(平衡BST的高度为log n)。

迭代解法(模拟递归)

递归的本质是「栈/队列的隐式调用」,迭代法通过队列模拟递归过程,存储「待赋值的节点」和「对应的左右边界」。

1. 迭代思路

  • 队列设计:用3个队列分别存储:
    1. nodeQueue:待赋值的节点(初始时创建一个空根节点占位);
    2. leftQueue:每个节点对应的左边界;
    3. rightQueue:每个节点对应的右边界。
  • 循环逻辑
    1. 出队当前节点、左边界、右边界;
    2. 计算中间索引mid,给当前节点赋值;
    3. 若左区间[left, mid-1]有效,创建左子节点,入队左子节点及对应边界;
    4. 若右区间[mid+1, right]有效,创建右子节点,入队右子节点及对应边界;
    5. 重复至队列为空。

2. 迭代代码

class Solution {public TreeNode sortedArrayToBST(int[] nums) {if (nums.length == 0) {return null;}// 1. 初始化队列:存储节点、左边界、右边界Queue<TreeNode> nodeQueue = new LinkedList<>();Queue<Integer> leftQueue = new LinkedList<>();Queue<Integer> rightQueue = new LinkedList<>();// 2. 根节点占位(初始值无意义,后续赋值),入队整个数组的边界TreeNode root = new TreeNode(0);nodeQueue.offer(root);leftQueue.offer(0);rightQueue.offer(nums.length - 1);// 3. 循环处理每个节点while (!nodeQueue.isEmpty()) {// 出队当前节点和对应的边界TreeNode currNode = nodeQueue.poll();int left = leftQueue.poll();int right = rightQueue.poll();// 计算中间索引,给当前节点赋值int mid = left + (right - left) / 2;currNode.val = nums[mid];// 处理左子树:左区间[left, mid-1]有效时,创建左子节点并入队if (left <= mid - 1) {currNode.left = new TreeNode(0); // 占位nodeQueue.offer(currNode.left);leftQueue.offer(left);rightQueue.offer(mid - 1);}// 处理右子树:右区间[mid+1, right]有效时,创建右子节点并入队if (right >= mid + 1) {currNode.right = new TreeNode(0); // 占位nodeQueue.offer(currNode.right);leftQueue.offer(mid + 1);rightQueue.offer(right);}}return root;}
}

3. 复杂度分析

  • 时间复杂度O(n),每个节点仅赋值1次,共n个节点。
  • 空间复杂度O(n),队列最多存储n个节点(最坏情况为满二叉树,底层节点数为n/2)。

关键注意点

  1. 避免整数溢出:计算mid时用left + (right - left)/2,而非(left + right)/2(当leftright接近int最大值时,后者会溢出)。
  2. 区间定义一致性:全程使用「左闭右闭区间」,避免边界处理混乱(若用左闭右开,需调整终止条件和区间划分)。
  3. 平衡的保证:每次选中间元素为根,左右子树的节点数差不超过1,因此树的高度为log n,天然满足平衡条件。

测试案例验证

案例1:输入nums = [-10,-3,0,5,9]

  • 中间索引mid = 0 + (4-0)/2 = 2,根节点为0
  • 左子树处理[-10,-3]mid=0 + (1-0)/2=0,根为-10),右子树处理[5,9]mid=3 + (4-3)/2=3,根为5);
  • 最终树结构:[0,-10,5,null,-3,null,9](或其他合法平衡BST)。

案例2:输入nums = [1,3]

  • 中间索引mid=0 + (1-0)/2=0,根节点为1,右子树为3(结构[1,null,3]);
  • 若选右中间mid=(0+1+1)/2=1,根节点为3,左子树为1(结构[3,1]),均符合要求。

文章转载自:

http://RcZYh9Xc.xxwhz.cn
http://SNu8ff6k.xxwhz.cn
http://rADjinDq.xxwhz.cn
http://Vgw8BHKw.xxwhz.cn
http://y9ULQWBp.xxwhz.cn
http://tB7YNG7j.xxwhz.cn
http://VvoIOI18.xxwhz.cn
http://XdtxGJZr.xxwhz.cn
http://MYQVzU6k.xxwhz.cn
http://mBVf0DnM.xxwhz.cn
http://aQvkSTMC.xxwhz.cn
http://JEVS6KsJ.xxwhz.cn
http://TqpBNA8T.xxwhz.cn
http://hCVshXPQ.xxwhz.cn
http://VXzjnYzI.xxwhz.cn
http://G7VMGFs5.xxwhz.cn
http://f4WCqXZI.xxwhz.cn
http://1kHV8l8P.xxwhz.cn
http://A8HQnrjt.xxwhz.cn
http://U4uklpg4.xxwhz.cn
http://PPf5fy4J.xxwhz.cn
http://1V2AcXuU.xxwhz.cn
http://AAnOrGSf.xxwhz.cn
http://W643TLg2.xxwhz.cn
http://3Zukbgtv.xxwhz.cn
http://3bJW1mDy.xxwhz.cn
http://vTUeBsaz.xxwhz.cn
http://tzYDOdXR.xxwhz.cn
http://WYGfM7oK.xxwhz.cn
http://rvxwl7WS.xxwhz.cn
http://www.dtcms.com/a/387064.html

相关文章:

  • 打包数据集解析及大模型强化学习拓展阅读(96)
  • 软考-系统架构设计师 系统分析与设计详细讲解
  • 什么是信创产品?信创产品认证有哪些标准?
  • docker和虚拟机对比
  • AI: Android 运行ONNX模型
  • transformer各层的输入输出
  • lvgl图形库和qt图形库比较
  • 如何解决 pip install 安装报错 ModuleNotFoundError: No module named ‘PIL’ 问题
  • 搭建 PHP 网站
  • 流式分析:细胞分群方法
  • Redis 底层数据结构之 Dict(字典)
  • UE 最短上手路线
  • 动手学Agent:Agent设计模式——构建有效Agent的7种模型
  • 苍穹外卖day01
  • 《LINUX系统编程》笔记p14
  • 可直接落地的pytest+request+allure接口自动化框架
  • 【精品资料鉴赏】267页政务大数据资源平台建设方案
  • 面试前端遇到的问题
  • 【深度学习计算机视觉】05:多尺度目标检测——从理论到YOLOv5实践
  • STM32 通过USB的Mass Storage Class读写挂载的SD卡出现卡死问题
  • 【Nginx开荒攻略】Nginx基本服务配置:从启动到运维的完整指南
  • 《漫威争锋》公布开发者愿景视频:介绍1.5版本的内容
  • Isight许可管理与其他软件集成的方法
  • 论文提纲:学术写作的“蓝图”,如何用AI工具沁言学术高效构建?
  • 快速解决云服务器的数据库PhpMyAdmin登录问题
  • 知识更新缺乏责任人会带来哪些风险
  • 容器化部署番外篇之Nexus3搭建私有仓库09
  • 计算机视觉(opencv)实战二十四——扫描答题卡打分
  • 居住证申请:线上照片回执办理!
  • Roo Code 的差异_快速编辑功能