LeetCode538. 把二叉搜索树转换为累加树

538. 把二叉搜索树转换为累加树

文章目录

      • [538. 把二叉搜索树转换为累加树](https://leetcode.cn/problems/convert-bst-to-greater-tree/)
        • 一、题目
        • 二、题解
          • 方法一:递归(中序遍历与节点更新)
          • 方法二:反向中序遍历与累加更新:更简洁的解法
          • 方法三:迭代(反向中序遍历)


一、题目

给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(Greater Sum Tree),使每个节点 node 的新值等于原树中大于或等于 node.val 的值之和。

提醒一下,二叉搜索树满足下列约束条件:

  • 节点的左子树仅包含键 小于 节点键的节点。
  • 节点的右子树仅包含键 大于 节点键的节点。
  • 左右子树也必须是二叉搜索树。

示例 1:

img

输入:[4,1,6,0,2,5,7,null,null,null,3,null,null,null,8]
输出:[30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]

示例 2:

输入:root = [0,null,1]
输出:[1,null,1]

示例 3:

输入:root = [1,0,2]
输出:[3,3,2]

示例 4:

输入:root = [3,2,4,1]
输出:[7,9,4,10]

提示:

  • 树中的节点数介于 0104 之间。
  • 每个节点的值介于 -104104 之间。
  • 树中的所有值 互不相同
  • 给定的树为二叉搜索树。

二、题解

方法一:递归(中序遍历与节点更新)

针对这个问题,我们可以考虑通过中序遍历来获取有序的节点值,然后从大到小更新节点的值,以满足累加树的要求。

算法思路

  1. 创建一个空的向量 array 用于存储中序遍历得到的有序节点值。

  2. 执行中序遍历函数 traversal_vec(root, array),该函数会将二叉搜索树的节点值按照从小到大的顺序存储在 array 中。

  3. array 的倒数第二个元素开始,将每个元素与其后一个元素相加,以便得到累加和。这一步保证了在累加树中,每个节点的值等于原树中大于或等于该节点值的所有节点值之和。

  4. 执行函数 traversal_res(root, array),该函数会将更新后的累加和值赋给二叉搜索树的每个节点。

  5. 返回更新后的二叉搜索树。

具体实现

以下是对每个步骤的详细实现:

class Solution {
public:
    int i = 0;
    
    // 中序遍历获取有序节点值并存储在array中
    void traversal_vec(TreeNode *root, vector<int> &array){
        if(root == nullptr) return;
        traversal_vec(root->left, array);
        array.push_back(root->val);
        traversal_vec(root->right, array);
    }
    
    // 更新节点值为累加和
    void traversal_res(TreeNode *root, vector<int>& array){
        if(root == nullptr) return;
        traversal_res(root->left, array);
        root->val = array[i++];
        traversal_res(root->right, array);
    }
    
    TreeNode* convertBST(TreeNode* root) {
        if(root == nullptr) return nullptr;
        
        vector<int> array;
        
        // 获取有序节点值
        traversal_vec(root, array);
        
        // 计算累加和
        for(int j = array.size() - 2; j >= 0; j--){
            array[j] += array[j+1];
        }
        
        // 更新节点值为累加和
        traversal_res(root, array);
        
        return root;
    }
};

或者将i作为参数传入traversal_res()也行:

class Solution {
public:
    void traversal_vec(TreeNode *root, vector<int> &array) {
        if (root == nullptr) return;
        traversal_vec(root->left, array);
        array.push_back(root->val);
        traversal_vec(root->right, array);
    }

    int traversal_res(TreeNode *root, int i, const vector<int> &array) {
        if (root == nullptr) return i;
        
        i = traversal_res(root->left, i, array);
        root->val = array[i];
        i++;
        i = traversal_res(root->right, i, array);
        
        return i;
    }

    TreeNode* convertBST(TreeNode* root) {
        if (root == nullptr) return nullptr;
        vector<int> array;
        traversal_vec(root, array);
        for (int j = array.size() - 2; j >= 0; j--) {
            array[j] += array[j + 1];
        }
        traversal_res(root, 0, array);
        return root;
    }
};

算法分析

  • 时间复杂度:算法的时间复杂度主要由两个部分构成:中序遍历和更新节点值。中序遍历需要访问每个节点一次,而更新节点值也需要访问每个节点一次。因此,算法的时间复杂度为 O(N),其中 N 是节点的数量。

  • 空间复杂度:算法的空间复杂度主要由中序遍历时存储节点值的数组 array 所占用的空间。在最坏的情况下,数组的大小为 N,因此空间复杂度为 O(N)。除此之外,递归调用栈也会占用一些空间,但是在二叉搜索树的情况下,递归调用栈的最大深度不会超过树的高度,因此额外空间的使用不会超过 O(log N)。

方法二:反向中序遍历与累加更新:更简洁的解法

算法思路

这个算法采用了一种不同的方法来实现二叉搜索树到累加树的转换。通过反向中序遍历(从右子树到左子树),我们可以更方便地得到大于当前节点值的节点值之和,然后直接更新节点值,从而获得累加树。

具体实现

class Solution {
public:
    // 反向中序遍历并更新节点值
    void convertBSTHelper(TreeNode* root, int& sum) {
        if(root == nullptr) return;
        
        convertBSTHelper(root->right, sum); // 先处理右子树
        sum += root->val; // 更新累加和
        root->val = sum; // 更新节点值
        convertBSTHelper(root->left, sum); // 处理左子树
    }
    
    TreeNode* convertBST(TreeNode* root) {
        if(root == nullptr) return nullptr;
        
        int sum = 0;
        convertBSTHelper(root, sum);
        return root;
    }
};

算法分析

  • 时间复杂度:算法的时间复杂度主要由中序遍历和更新节点值组成。每个节点都会被访问一次且只访问一次,因此时间复杂度为 O(N),其中 N 是节点的数量。
  • 空间复杂度:算法的空间复杂度由递归调用栈所占用的空间决定。在二叉搜索树的情况下,递归调用栈的最大深度不会超过树的高度,因此额外空间的使用不会超过 O(log N)。
方法三:迭代(反向中序遍历)

算法思路

这个算法采用了反向中序遍历的方式,通过栈来实现,来构建累加树。遍历的过程中,我们从最大值开始,逐步向较小值移动,同时将大于等于当前节点值的所有节点值累加起来,然后将该累加值赋予当前节点,最终构建出累加树。

具体实现

class Solution {
private:
    int previousValue; // 记录前一个节点的值
    
    // 反向中序遍历并更新节点值
    void reverseInorderTraversal(TreeNode* root) {
        stack<TreeNode*> nodeStack;
        TreeNode* current = root;
        
        while (current != nullptr || !nodeStack.empty()) {
            if (current != nullptr) {
                nodeStack.push(current);
                current = current->right; // 右子树
            } else {
                current = nodeStack.top(); // 弹出栈顶节点
                nodeStack.pop();
                
                // 更新节点值
                current->val += previousValue;
                previousValue = current->val;
                
                current = current->left; // 左子树
            }
        }
    }
    
public:
    TreeNode* convertBST(TreeNode* root) {
        previousValue = 0; // 初始化前一个节点的值
        reverseInorderTraversal(root); // 反向中序遍历更新节点值
        return root;
    }
};

算法分析

  • 时间复杂度:算法的时间复杂度主要由反向中序遍历过程构成。每个节点会被访问一次且只访问一次,因此时间复杂度为 O(N),其中 N 是节点的数量。

  • 空间复杂度:算法的空间复杂度由栈所占用的空间决定。在最坏情况下,栈的大小可能达到树的高度,即 O(log N)。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Java“牵手”快手商品列表数据,关键词搜索快手商品数据接口,快手API申请指南

快手商城是一个网上批发购物平台&#xff0c;售卖各类商品&#xff0c;包括服装、鞋类、家居用品、美妆产品、电子产品等。要获取快手商品列表和商品详情页面数据&#xff0c;您可以通过开放平台的接口或者直接访问快手商城的网页来获取商品详情信息。以下是两种常用方法的介绍…

macOS使用命令行连接Oracle(SQL*Plus)

Author: histonevonzohomail.com Date: 2023/08/25 文章目录 SQL\*Plus安装下载环境配置 SQL\*Plus远程连接数据库参考文献 原文地址&#xff1a;https://histonevon.top/archives/oracle-mac-sqlplus数据库安装&#xff1a;Docker安装Oracle数据库 (histonevon.top) SQL*Plus…

Linux 发行版 Debian 宣布支持龙芯 LoongArch 架构

近期&#xff0c;龙芯发布了 3A6000 桌面处理器&#xff0c;芯片的性能又一次大幅度提升&#xff0c;成为国产芯片的又一里程碑。 同期&#xff0c;LoongArch 架构的生态建设也迅速提升&#xff0c;开源网络引导固件 iPXE、QQ Linux 版、摩尔线程等软硬件都官宣支持龙芯 Loong…

pytest笔记: pytest单元测试框架

第一步&#xff1a;安装 和查看版本 pycharm settings 查看 第二步&#xff1a; 编写test_example.py def inc(x):return x1 def test_answer():assert inc(4) 5 第三步&#xff1a;在当前路径下执行pytest 命令 PS E:\data\web测试\Selenium3自动化测试实战——基于Pyth…

Ubuntu安装RabbitMQ

一、安装 更新系统软件包列表&#xff1a; sudo apt update安装RabbitMQ的依赖组件和GPG密钥&#xff1a; sudo apt install -y curl gnupg curl -fsSL https://github.com/rabbitmq/signing-keys/releases/download/2.0/rabbitmq-release-signing-key.asc | sudo gpg --dearmo…

华为MateBook14 2020款 锐龙版R5集显触屏(KLVL-WFH9)原装Win10系统工厂模式安装包

系统自带F10智能还原功能、带指纹、显卡、声卡、网卡等所有驱动、出厂主题壁纸、系统属性华为专属LOGO标志、Office办公软件、华为电脑管家等预装程序 所需要工具&#xff1a;16G或以上的U盘 文件格式&#xff1a;rar压缩包 文件大小&#xff1a;11GB 链接&#xff1a;htt…

【IMX6ULL驱动开发学习】12.Linux SPI驱动实战:DAC驱动设计流程

基础回顾&#xff1a; 【IMX6ULL驱动开发学习】10.Linux I2C驱动实战&#xff1a;AT24C02驱动设计流程_阿龙还在写代码的博客-CSDN博客 【IMX6ULL驱动开发学习】11.Linux之SPI驱动_阿龙还在写代码的博客-CSDN博客 一、编写驱动 查看芯片手册&#xff0c;有两种DAC数据格式&a…

AI + Milvus:将时尚应用搭建进行到底

在上一篇文章中&#xff0c;我们学习了如何利用人工智能技术&#xff08;例如开源 AI 向量数据库 Milvus 和 Hugging Face 模型&#xff09;寻找与自己穿搭风格相似的明星。在这篇文章中&#xff0c;我们将进一步介绍如何通过对上篇文章中的项目代码稍作修改&#xff0c;获得更…

Spring Boot(Vue3+ElementPlus+Axios+MyBatisPlus+Spring Boot 前后端分离)【六】

&#x1f600;前言 本篇博文是关于Spring Boot(Vue3ElementPlusAxiosMyBatisPlusSpring Boot 前后端分离)【六】&#xff0c;希望你能够喜欢 &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨犀&#xff0c;希望我的文章…

Vue2向Vue3过度核心技术工程化开发和脚手架

目录 1 工程化开发和脚手架1.1 开发Vue的两种方式1.2.脚手架Vue CLI 2 项目目录介绍和运行流程2.1 项目目录介绍2.2 运行流程 3 组件化开发4 根组件 App.vue4.1 根组件介绍4.2 组件是由三部分构成4.3 总结 5 普通组件的注册使用-局部注册5.1 特点&#xff1a;5.2 步骤&#xff…

17.3 【Linux】systemctl 针对 service 类型的配置文件

17.3.1 systemctl 配置文件相关目录简介 服务的管理是通过 systemd&#xff0c;而 systemd 的配置文件大部分放置于/usr/lib/systemd/system/ 目录内。但是 Red Hat 官方文件指出&#xff0c; 该目录的文件主要是原本软件所提供的设置&#xff0c;建议不要修改&#xff01;而要…

[EasyX库安装介绍讲解】超详细入门级

基本说明 EasyX 是针对 C 的图形库&#xff0c;可以帮助 C/C 初学者快速上手图形和游戏编程。 比如&#xff0c;可以基于 EasyX 图形库很快的用几何图形画一个房子&#xff0c;或者一辆移动的小车&#xff0c;可以编写俄罗斯方块、贪吃蛇、黑白棋等小游戏&#xff0c;可以练习…

android logcat问题 怎么换成旧版

参考 如果想切换回旧版LOGCAT&#xff0c;按照下方步骤设置即可 File->Settings->Expermental->Logcat->Enable new Logcat tool window&#xff1a;取消勾选 设置好后上方会有一个Toast&#xff0c;询问你是否使用新版logcat&#xff0c;关掉即可 最新测试版移…

【Cesium创造属于你的地球】实现地球展示、灵活进行坐标转换、视角切换

大家好&#xff0c;我是AIC山鱼&#xff01;&#x1f449;这是我的主页 &#x1f40b;作为CSDN博主和前端优质创作者✍&#xff0c;我致力于为大家带来新颖、脱俗且有趣的内容。 &#x1f431;我还创建了山鱼社区&#xff0c;这是一个独特的社区&#x1f3e0;&#xff0c;&…

激活潜能:探索职场中的自我效能感之道

引言:自我效能感的定义与重要性 自我效能感,简而言之,是个体对自己能够成功完成某项任务的信心。这种信心不仅影响我们的思考方式和情感,还影响我们的行为和动机。在职场中,高自我效能感的人往往更有动力,更能够面对挑战,而低自我效能感的人则可能会避免面对困难,容易…

微信小程序如何实现页面传参和页面传递多个参数

前言 只要你的小程序超过一个页面那么可能会需要涉及到页面参数的传递&#xff0c;下面我总结了 4 种页面方法。 下面时多个参数页面传参的方式 let loveJSON.stringify(this.data.totle);let youJSON.stringify(this.data.totleId)let csdnJSON.stringify(this.data.totleP…

瞬态电压抑制器(TVS)汽车级 SZESD9B5.0ST5G 工作原理、特性参数、封装形式

什么是汽车级TVS二极管&#xff1f; TVS二极管是一种用于保护电子电路的电子元件。它主要用于电路中的过电压保护&#xff0c;防止电压过高而损坏其他部件。TVS二极管通常被称为“汽车级”是因为它们能够满足汽车电子系统的特殊要求。 在汽车电子系统中&#xff0c;由于车辆启…

Golang Gorm 一对多的添加

一对多的添加有两种情况&#xff1a; 一种是添加用户的时候同时创建文章其次是创建文章关联已经存在的用户。 package mainimport ("gorm.io/driver/mysql""gorm.io/gorm" )// User 用户表 一个用户拥有多篇文章 type User struct {ID int64Name …

SpringBoot整合thymeleaf

JavaEE领域有几种常用的模板引擎: Jsp, Thymeleaf, Freemarker, Velocity等.对于前端页面渲染效率来说 JSP 其实还是最快的, Velocity次之.Thymeleaf虽然渲染效率不是很快,但语法比较轻巧. Thymeleaf 支持html5标准, Thymeleaf页面无需部署到servlet开发到服务器上,以 .html 后…

JVM,JRE和JDK的区别

JVM&#xff0c;JRE和JDK的区别 JVM(Java Virtual Machine&#xff0c;Java虚拟机)JREJRE目录结构 JDK JVM(Java Virtual Machine&#xff0c;Java虚拟机) Java程序的跨平台特性主要是指字节码文件可以在任何具有Java虚拟机的计算机或者电子设备上运行&#xff0c;Java虚拟机中…