LeetCode 算法:将有序数组转换为二叉搜索树 c++

原题链接🔗:将有序数组转换为二叉搜索树
难度:简单⭐️

题目

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

平衡二叉搜索树

  • 平衡二叉搜索树(Balanced Binary Search Tree,简称BBST)是一种特殊的二叉搜索树,它在保持二叉搜索树的所有性质的同时,还保证了树的高度尽可能地小。这通常通过在插入和删除操作后重新平衡树来实现,以确保树的任何两个子树的高度差不会超过1。

  • 平衡二叉搜索树的一个常见实现是AVL树,它是一种自平衡的二叉搜索树,其名称来源于其发明者Adelson-Velsky和Landis。AVL树在每次插入或删除操作后,都会进行必要的旋转操作来保持树的平衡。

  • AVL树的平衡操作包括四种基本的旋转:

    • 左旋(Left Rotation):当节点的右子树比左子树高时,进行左旋来减少树的高度。
    • 右旋(Right Rotation):当节点的左子树比右子树高时,进行右旋来减少树的高度。
    • 左右旋(Left-Right Rotation):当节点的左子树的右子树比左子树高时,首先对左子树进行右旋,然后对节点进行左旋。
    • 右左旋(Right-Left Rotation):当节点的右子树的左子树比右子树高时,首先对右子树进行左旋,然后对节点进行右旋。
  • AVL树的每个节点除了存储值和指向左右子节点的指针外,还存储了一个平衡因子(balance factor),通常是左子树高度和右子树高度的差值。节点的平衡因子只能是-1、0或1。

题解

递归法

  1. 解题思路

将一个有序数组转换为二叉搜索树(BST)的解题思路基于二叉搜索树的性质:左子树上所有节点的值 < 根节点的值 < 右子树上所有节点的值。对于一个有序数组,我们可以利用数组的有序性来快速确定根节点和左右子树的划分点。

以下是解题步骤:

  • 确定根节点:对于有序数组,中间元素(数组长度的一半)是一个很好的根节点候选,因为它可以很好地维持左右子树的大小平衡。

  • 递归构建左右子树:使用数组下标来划分,左子树包含从数组开始到根节点前的部分,右子树包含从根节点的下一个元素到数组末尾的部分。

  • 递归终止条件:当子数组为空时,返回null。

  • 构建树:对于每个子数组,重复上述步骤,递归地构建左右子树。

  • 返回根节点:递归结束时,返回构建的树的根节点。

下面是具体的算法逻辑:

  • 定义一个递归函数sortedArrayToBST,它接收有序数组的起始索引和结束索引作为参数。
  • 计算中间索引mid:mid = (start+ end) / 2
  • 使用mid索引处的值创建一个新的树节点。
  • 递归地调用sortedArrayToBST来构建左子树,使用start和mid - 1作为新的参数。
  • 递归地调用sortedArrayToBST来构建右子树,使用mid + 1和end作为新的参数。
  • 将左子树和右子树分别赋值给新创建的根节点的左右子节点。
  • 返回根节点。
  1. 复杂度:时间复杂度O(n),空间复杂度O(logn)。

  2. c++ demo

#include <iostream>
#include <vector>// 定义二叉树节点
struct TreeNode {int val;TreeNode* left;TreeNode* right;TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};// 将有序数组转换为二叉搜索树的函数
class Solution {
public:TreeNode* sortedArrayToBST(std::vector<int>& nums) {return sortedArrayToBSTHelper(nums, 0, nums.size() - 1);}private:TreeNode* sortedArrayToBSTHelper(std::vector<int>& nums, int start, int end) {if (start > end) {return nullptr;}// 选择中间的元素作为根节点int mid = start + (end - start) / 2;TreeNode* node = new TreeNode(nums[mid]);// 递归地构建左子树和右子树node->left = sortedArrayToBSTHelper(nums, start, mid - 1);node->right = sortedArrayToBSTHelper(nums, mid + 1, end);return node;}
};// 辅助函数:中序遍历二叉树并打印节点值
void inorderTraversal(TreeNode* node) {if (!node) return;inorderTraversal(node->left);std::cout << node->val << " ";inorderTraversal(node->right);
}// 辅助函数:释放二叉树内存
void deleteTree(TreeNode* node) {if (!node) return;deleteTree(node->left);deleteTree(node->right);delete node;
}int main() {// 创建Solution实例Solution solution;// 有序数组std::vector<int> nums = { -10, -3, 0, 5, 9 };// 将有序数组转换为BSTTreeNode* root = solution.sortedArrayToBST(nums);// 中序遍历BST并打印节点值std::cout << "Inorder traversal of the constructed BST:" << std::endl;inorderTraversal(root);std::cout << std::endl;// 释放二叉树内存deleteTree(root);return 0;
}
  • 输出结果:

Inorder traversal of the constructed BST:
-10 -3 0 5 9

  1. demo 仓库地址:sortedArrayToBST

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/35050.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

LinkedBlockingQueue 原理

基本的入队出队 public class LinkedBlockingQueue<E> extends AbstractQueue<E>implements BlockingQueue<E>, java.io.Serializable {static class Node<E> {E item;/*** 下列三种情况之一* - 真正的后继节点* - 自己, 发生在出队时* - null, 表示是…

解决因国内各大镜像站关停导致无法下载镜像的问题

方法1 配置镜像加速 vim /etc/docker/daemon.json {"exec-opts": ["native.cgroupdriversystemd"],"registry-mirrors": ["https://0fivaqt3.mirror.aliyuncs.com","https://hub.appifa.com","https://dockerproxy.co…

[面试题]Zookeeper

[面试题]Java【基础】[面试题]Java【虚拟机】[面试题]Java【并发】[面试题]Java【集合】[面试题]MySQL[面试题]Maven[面试题]Spring Boot[面试题]Spring Cloud[面试题]Spring MVC[面试题]Spring[面试题]MyBatis[面试题]Nginx[面试题]缓存[面试题]Redis[面试题]消息队列[面试题]…

windows桌面运维----第九天

1、新的电脑需要安装哪些驱动&#xff1a; 显卡驱动、声卡驱动、主板驱动、网卡驱动、打印机驱动、外设驱动、 2、网络打印机如何开启打印机共享核客户端连接共享打印机&#xff1a; 一、打开控制面板并定位到设备和打印机&#xff1a; 首先&#xff0c;我们在电脑桌面上找…

【C/C++】Code Style

命名规范 代码元素命名风格注释Namespaceunder_scored为了跟类名做区分Class nameCamelCase为了跟标准库的类名做区分 (建议不要使用大写"C" 或者 “T” 作为前缀)Function namecamelCase小写开头的函数名基本是通用的&#xff0c;除了.Net自成一格Parameters/Local…

【C语言】操作符(上)

目录 1. 操作符的分类 2. 原码、反码、补码 3. 移位操作符 3.1 左移操作符 3.2 右移操作符 4. 位操作符&#xff1a;&、|、^、~ 5. 单目操作符 6. 逗号表达式 最近准备期末考试&#xff0c;好久不见啦&#xff0c;现在回归—— 正文开始—— 1. …

fc-list命令使用指南

fc-list命令使用指南 一、什么是fc-list? fc-list是FontConfig库的一部分&#xff0c;最初为Linux和其他Unix-like系统开发。我们可以用这个命令行快速查询和列出系统中安装的字体。 现在&#xff0c;Windows用户也集成了这个工具&#xff0c;所以我们来讲解一下用法。 二、…

路经src里的文件是?

说明&#xff1a; src 目录指的是源代码&#xff08;source code&#xff09;目录&#xff0c;存放项目应用的源代码&#xff0c;包含项目的逻辑和功能实现&#xff0c;实际上线之后在浏览器中跑的代码就是它们 apis - 业务接口assets - 静态资源 &#xff08;图片&#xff09…

《昇思 25 天学习打卡营第 7 天 | 模型训练 》

《昇思 25 天学习打卡营第 7 天 | 模型训练 》 活动地址&#xff1a;https://xihe.mindspore.cn/events/mindspore-training-camp 签名&#xff1a;Sam9029 模型训练 本章节-结合前几张的内容所讲-算是一节综合实践 mindscope 框架使用张量 数据类型数据集下载与加载网络构建函…

mulesoft --环境安装与搭建

1.mavenjdkpostman 2.anypoint statdio 下载安装 下载 Anypoint Studio & Mule |骡子软件 (mulesoft.com) 填好基本信息后&#xff0c;会发邮件&#xff0c;在邮件中下载&#xff0c;跳到官网下载 3注册账号 Download Anypoint Studio & Mule | MuleSoft 4.Connect…

PostgreSQL 高可用性与容错性(十三)

1. 备份与恢复策略 1.1 数据备份 1.1.1 基于 pg_dump 的逻辑备份 pg_dump -U username -d dbname -f backup_file.sql 1.1.2 基于 pg_basebackup 的物理备份 pg_basebackup -U username -D /path/to/backup/directory -Ft -Xs -P -R 1.2 恢复数据库 1.2.1 恢复逻辑备份 …

详解 ClickHouse 的分片集群

一、简介 分片功能依赖于 Distributed 表引擎&#xff0c;Distributed 表引擎本身不存储数据&#xff0c;有点类似于 MyCat 之于 MySql&#xff0c;成为一种中间件&#xff0c;通过分布式逻辑表来写入、分发、路由来操作多台节点不同分片的分布式数据 ClickHouse 进行分片集群的…

C语言基础——函数(2)

ʕ • ᴥ • ʔ づ♡ど &#x1f389; 欢迎点赞支持&#x1f389; 文章目录 前言 一、return语句 二、数组做函数参数 三、嵌套调用和链式访问 3.1 嵌套调用 3.2 链式访问 四、函数声明和定义 4.1 单个文件 4.2 多个文件 总结 前言 大家好啊&#xff0c;继我们上一…

优化系统小工具

一款利用VB6编写的系统优化小工具&#xff0c;系统优化、桌面优化、清理垃圾、查找文件等功能。 下载:https://download.csdn.net/download/ty5858/89432367

构造,析构,垃圾回收

构造函数 基本概念 在实例化对象时 会调用的用于初始化的函数 如果不写&#xff0c;默认存在一个无参构造函数 构造函数的写法 1.没有返回值 2.函数名和类名必须相同 3.没有特殊需求时&#xff0c;一般都是public的 4.构造函数可以被重载 5.this代表当前调用该函数的对…

前端JS计算精度损失的问题

例子: 0.10.2 //0.30000000000000004 1.2-1 //0.19999999999999996 1.15*100 //114.99999999999999 1.2/0.2 //5.999999999999999 方式1 // 两个浮点数求和 function num_add(num1,num2){var r1,r2,m;try{r1 num1.toString().split(.)[1].length;}catch(e){r1 0;}try{r2num…

【UE5.3】笔记1

内容浏览器&#xff1a;存放项目中所有的资源&#xff1a;关卡、蓝图类...... 关卡--Map 至少有一个关卡&#xff0c;可以有多个关卡 -漫游 视野漫游&#xff1a;鼠标右键WASD QE 鼠标滑轮控制摄像机速度 运行&#xff0c;ESC退出运行,快捷键F8不停止运行单独弹出功能 -创…

计算机视觉全系列实战教程 (十三):图像形态学操作

1.基本概述 (1)What 图像的形态学操作的本质&#xff1a;集合间的运算 几何学 (2)Why(有什么用途&#xff09; 消除噪声、边缘提取、区域填充、细化和粗化、分割独立的图像元素、求图像梯度、求极大值区域或极小值区域等。 (3)Which(有哪些常见的形态学操作) A.膨胀 使得…

Express的模块化路由

Express的模块化路由是一种组织和管理路由的有效方式&#xff0c;它使得代码更加清晰、易于维护和扩展。 1. 模块化路由的概念 模块化&#xff1a;在编程中&#xff0c;模块化是将程序拆分成多个独立但相互依赖的模块&#xff0c;每个模块都包含特定的功能和数据。Express模块…