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

力扣题目链接(opens new window)

将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树。

本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 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】有序数组转换为二叉搜索树(构造二叉树)的更多相关文章

  1. LeetCode:将有序数组转换为二叉搜索树【108】

    LeetCode:将有序数组转换为二叉搜索树[108] 题目描述 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差 ...

  2. LeetCode 108. 将有序数组转换为二叉搜索树(Convert Sorted Array to Binary Search Tree) 14

    108. 将有序数组转换为二叉搜索树 108. Convert Sorted Array to Binary Search Tree 题目描述 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索 ...

  3. Java实现 LeetCode 108 将有序数组转换为二叉搜索树

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

  4. [LeetCode] 108. 将有序数组转换为二叉搜索树

    题目链接 : https://leetcode-cn.com/problems/convert-sorted-array-to-binary-search-tree/ 题目描述: 将一个按照升序排列的 ...

  5. 代码随想录算法训练营day23 | leetcode 669. 修剪二叉搜索树 ● 108.将有序数组转换为二叉搜索树 ● 538.把二叉搜索树转换为累加树

    LeetCode 669. 修剪二叉搜索树 分析1.0 递归遍历树时删除符合条件(不在区间中)的节点-如何遍历如何删除 如果当前节点大于范围,递归左树,反之右树 当前节点不在范围内,删除它,把它的子树 ...

  6. [leetcode-108,109] 将有序数组转换为二叉搜索树

    109. 有序链表转换二叉搜索树 Given a singly linked list where elements are sorted in ascending order, convert it ...

  7. LeetCode(108):将有序数组转换为二叉搜索树

    Easy! 题目描述: 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: 给定有序数组 ...

  8. [LeetCode]105. 从前序与中序遍历序列构造二叉树(递归)、108. 将有序数组转换为二叉搜索树(递归、二分)

    题目 05. 从前序与中序遍历序列构造二叉树 根据一棵树的前序遍历与中序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 题解 使用HashMap记录当前子树根节点在中序遍历中的位置,方便每次 ...

  9. LeetCode刷题笔记-递归-将有序数组转换为二叉搜索树

    题目描述 将一个按照升序排列的有序数组,转换为一棵高度平衡二叉搜索树. 本题中,一个高度平衡二叉树是指一个二叉树每个节点 的左右两个子树的高度差的绝对值不超过 1. 示例: 给定有序数组: [-10, ...

  10. LeetCode【108. 将有序数组转换为二叉搜索树】

    又是二叉树,最开始都忘记了二叉搜索树是什么意思,搜索了一下: 二叉搜索树:左节点都小于右节点,在这里就可以考虑将数组中的中间值作为根节点 平衡二叉树:就是左右节点高度不大于1 树就可以想到递归与迭代, ...

随机推荐

  1. [转帖]Linux磁盘I/O(二):使用vm.dirty_ratio和vm.dirty_background_ratio优化磁盘性能

    文件缓存是一项重要的性能改进,在大多数情况下,读缓存在绝大多数情况下是有益无害的(程序可以直接从RAM中读取数据).写缓存比较复杂,Linux内核将磁盘写入缓存,过段时间再异步将它们刷新到磁盘.这对加 ...

  2. [转帖]并发控制- sched_yield 函数

    函数说明 函数原型 #include <sched.h> int sched_yield(void); 1 2 sched_yield的作用是让出处理器,调用时会导致当前线程放弃CPU,进 ...

  3. k8s的内部服务通信

    首先看看 k8s 集群中内部各个服务互相访问的方法 Cluster IP Kubernetes以Pod作为应用部署的最小单位.Kubernetes会根据Pod的声明对其进行调度,包括创建.销毁.迁移. ...

  4. 【JS 逆向百例】Fiddler 插件 Hook 实战,某创帮登录逆向

    关注微信公众号:K哥爬虫,QQ交流群:808574309,持续分享爬虫进阶.JS/安卓逆向等技术干货! 声明 本文章中所有内容仅供学习交流,抓包内容.敏感网址.数据接口均已做脱敏处理,严禁用于商业用途 ...

  5. LINUX安装和配置

    本篇文章为本人从零开始学习linux的学习心得,其中包含了 部署虚拟环境安装linux系统 .其中若有错误之处,请读者积极指出,让本人与读者共同进步. 第一章 部署虚拟环境安装linux系统及配置网路 ...

  6. 基于OpenIM 实现聊天机器人功能

    ### 简要描述 使用 OpenIM 中的 Webhook 机制实现聊天机器人功能.发送文本消息或图片消息给聊天机器人后,机器人会返回相同的消息.开发者可以替换此逻辑,在LangChain框架上调用L ...

  7. 从python3到python2的踩坑

    为什么要从py3到py2 背景:之前自学写过一些py3,而且我写的工具是基于python3来写的,但是公司项目是使用python2版本,希望已有工具或者新写的工具能同时在py2和py3上执行,所以记录 ...

  8. 爱了爱了!推荐一个Github 70k+点赞的Java学习指南!

    大家好,我是 Guide 哥!今天给大家推荐一个非常不错的 Java 教程类开源项目-JavaGuide ,Github 地址: https://github.com/Snailclimb/JavaG ...

  9. 详解 & 0xff 的意义及作用

    首先我们要都知道, &表示按位与,只有两个位同时为1,才能得到1, 0x代表16进制数,0xff表示的数二进制1111 1111 占一个字节.和其进行&操作的数,最低8位,不会发生变化 ...

  10. CF1886

    A 分类讨论. B 二分. C 题意:给定一个字符串 \(s\).记 \(s_i\) 为将 \(s\) 删去 \(i\) 个字符,使得剩余字符串字典序最小得到的字符串.令 \(S=s_0+s_1+\d ...