【LeetCode二叉树#19】有序数组转换为二叉搜索树(构造二叉树)
将有序数组转换为二叉搜索树
将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。
本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1。
示例:

思路
本题还是考察的构建二叉树
之前也有做过类似的题目,基本上来说,构造二叉树就是按照题目规则找根节点,然后调用递归不断构造出其左右子树即可
那么,本题的规则是什么?
题目要求我们将升序排列的有序数组,转换为一棵高度平衡二叉搜索树
因此,可以用数组的中间值为根节点来构造二叉搜索树
如果之后再来复习,肯定会想:如果中间值有两个怎么办
那现在先举个例子说明一下:
[1,2,3,4,5,6]
这里如果取中间值会有两个数,分别是3和4
实际上这不影响我们去构造一颗高度平衡二叉搜索树,因为不论选3还是4作为根节点,其左或右子树多出的一个节点也不会破坏高度的平衡
在这里,我们默认取左边的值(后面会说明原因)
确定了根节点之后,还是像之前的构建二叉树的题目,通过递归不断分割左右区间,进而构建出根节点的左右子树
代码
分析
使用递归法
1、确定递归函数的参数和返回值
不要一写参数就下意识的填根节点,这里都还没有找出根节点呢
因为要通过分割数组来构建二叉树,所以输入参数中肯定有数组nums,以及用于分割的左右区间
并且,我们需要返回的是一颗二叉树,那么返回值显然就是该树的根节点了
TreeNode* traversal(vector<int> nums, int left, int right){
}
2、确定终止条件
同理,不要一写终止条件就下意识的root==NULL
这里的终止条件应该与左右边界有关
即当 left > right 时应该结束
TreeNode* traversal(vector<int> nums, int left, int right){
//确定终止条件
if(left > right) return NULL;
}
3、确定单层处理逻辑
现在要开始取数组的中间值并分割数组
TreeNode* traversal(vector<int> nums, int left, int right){
//确定终止条件
if(left > right) return NULL;
//确定单层处理逻辑
//取中间值
int mid = (right - left)/2 + left;
}
为什么这样取中间值?
因为如果直接(right + left) / 2,当right、left均为int下的最大值,会导致数据溢出
上述方法可以避免这种问题,详见
TreeNode* traversal(vector<int> nums, int left, int right){
//确定终止条件
if(left > right) return NULL;
//确定单层处理逻辑
//取中间值
int mid = (right - left)/2 + left;
//创建根节点
TreeNode* root = new TreeNode(nums[mid]);
//调用递归继续构建左右子树
root->left = traversal(nums, left, mid - 1);//跳过mid
root->right = traversal(nums, mid + 1, right);
return root;
}
注意,在分割数组时要跳过mid处的值
完整代码
class Solution {
public:
//确定递归函数的参数与返回值
TreeNode* traversal(vector<int>& nums, int left, int right){
//确定终止条件
if(left > right) return NULL;
//确定单层处理逻辑
//先找到数组里的中间值
int mid =(right - left) / 2 + left;//防止数据溢出
//初始化根节点
TreeNode* root = new TreeNode(nums[mid]);
//递归处理分割后数组的左区间和右区间
//注意要跳过mid
root->left = traversal(nums, left, mid - 1);
root->right = traversal(nums, mid + 1, right);
return root;
}
TreeNode* sortedArrayToBST(vector<int>& nums) {
return traversal(nums, 0 , nums.size() - 1);
}
};
构造二叉树的注意事项
1、找根节点
一般来说,没有特殊规定就找中间值作为根节点
本题中要求构建的二叉树为高度平衡的二叉搜索树,正好选中间值可以满足条件
2、根本原理
总结一下这几题构造二叉树的套路,无外乎:找根节点、递归分割数组构建左右子树
值得注意的是,在本题中,我们没有对nums本身进行操作,而是利用其下标进行的分割
而在之前做的几题里,我们分割数组时使用了**新建数组的方式
【LeetCode二叉树#19】有序数组转换为二叉搜索树(构造二叉树)的更多相关文章
- LeetCode:将有序数组转换为二叉搜索树【108】
LeetCode:将有序数组转换为二叉搜索树[108] 题目描述 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差 ...
- LeetCode 108. 将有序数组转换为二叉搜索树(Convert Sorted Array to Binary Search Tree) 14
108. 将有序数组转换为二叉搜索树 108. Convert Sorted Array to Binary Search Tree 题目描述 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索 ...
- Java实现 LeetCode 108 将有序数组转换为二叉搜索树
108. 将有序数组转换为二叉搜索树 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: ...
- [LeetCode] 108. 将有序数组转换为二叉搜索树
题目链接 : https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/ 题目描述: 将一个按照升序排列的 ...
- 代码随想录算法训练营day23 | leetcode 669. 修剪二叉搜索树 ● 108.将有序数组转换为二叉搜索树 ● 538.把二叉搜索树转换为累加树
LeetCode 669. 修剪二叉搜索树 分析1.0 递归遍历树时删除符合条件(不在区间中)的节点-如何遍历如何删除 如果当前节点大于范围,递归左树,反之右树 当前节点不在范围内,删除它,把它的子树 ...
- [leetcode-108,109] 将有序数组转换为二叉搜索树
109. 有序链表转换二叉搜索树 Given a singly linked list where elements are sorted in ascending order, convert it ...
- LeetCode(108):将有序数组转换为二叉搜索树
Easy! 题目描述: 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: 给定有序数组 ...
- [LeetCode]105. 从前序与中序遍历序列构造二叉树(递归)、108. 将有序数组转换为二叉搜索树(递归、二分)
题目 05. 从前序与中序遍历序列构造二叉树 根据一棵树的前序遍历与中序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 题解 使用HashMap记录当前子树根节点在中序遍历中的位置,方便每次 ...
- LeetCode刷题笔记-递归-将有序数组转换为二叉搜索树
题目描述 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: 给定有序数组: [-10, ...
- LeetCode【108. 将有序数组转换为二叉搜索树】
又是二叉树,最开始都忘记了二叉搜索树是什么意思,搜索了一下: 二叉搜索树:左节点都小于右节点,在这里就可以考虑将数组中的中间值作为根节点 平衡二叉树:就是左右节点高度不大于1 树就可以想到递归与迭代, ...
随机推荐
- [转帖]shell脚本中$0 $1 $# $@ $* $? $ 的各种符号的意义
概述 shell中有两类字符,一类是普通字符,在Shell中除了本身的字面意思外没有其他特殊意义,即普通纯文本:另一类即元字符,是Shell的保留字符,在Shell中有着特殊的含义. 今天主要介绍一下 ...
- frp 的简单使用
在出差现场. 开着VPN 就没法用出差现场的网络, 想了想 好像 只能用 frp 来搞一下比较好 借了下同事的vps 进行相应的处理 进行简单的内容穿透工作. 1. 下载相关的文件. wget htt ...
- 学习: Linux的 date 命令
date 命令非常好用 多用 date --h 还是非常好的 获取 今天是今年的第多少天 最简单的办法 就是 date +%j 以后需要多学习 多利用 linux的帮助才可以呢. Usage: dat ...
- centos8上安装中文字符集
https://www.cnblogs.com/kaishirenshi/p/12669353.html yum install glibc-common yum install -y langpac ...
- 万能shell 简单查看已存在日志所有的启动记录
程序将日志 自动打包成了 gz 文件, 今天突然想查查所有的日志有没有相关关键字. 第一步解压缩所有的日志 cd 到相关目录 for i in `ls` ; do gzip -d $i ; done ...
- linux机制
cpu Cache 工作原理:文中对Cache的一致性提出了两种策略:基于监听的和基于目录的.前者是所有Cache均监听各个Cache的写操作,当一个Cache中的数据被写了,其处理方式有:写更新协议 ...
- 我们开源了一个轻量的 Web IDE UI 框架
我们开源了一个轻量的 Web IDE UI 框架 Molecule 一个轻量的 Web IDE UI 框架 简介 Molecule 是一个受 VS Code 启发,使用 React.js 构建的 We ...
- RedisSyncer同步引擎的设计与实现
RedisSyncer一款通过replication协议模拟slave来获取源Redis节点数据并写入目标Redis从而实现数据同步的Redis同步中间件. 该项目主要包括以下子项目: redis 同 ...
- uni-app快速导入自己需要的插件
在uni-app中快速导入自己需要的插件 在uni-app的官网上;找到自己需要的插件: 然后点击右侧顶部的[使用HX导入]这一步的前提是你必须要用自己的账好登录: 然后选择你要导入哪一个项目 然后就 ...
- 7.3 Windows驱动开发:内核监视LoadImage映像回调
在笔者上一篇文章<内核注册并监控对象回调>介绍了如何运用ObRegisterCallbacks注册进程与线程回调,并通过该回调实现了拦截指定进行运行的效果,本章LyShark将带大家继续探 ...