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

news2024/11/16 21:54:56

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)。

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

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

相关文章

作业人员护目镜佩戴自动识别

作业人员护目镜佩戴自动识别通过pythonyolo深度学习算法模型&#xff0c;作业人员护目镜佩戴自动识别利用布设摄像头并结合图像算法能够实时监测作业人员是否佩戴护目镜。一旦发现未佩戴的情况立即发出警告&#xff0c;并及时记录异常情况。在YOLOv1提出之前&#xff0c;R-CNN系…

iPhone手机如何删除照片应用程序的文稿与数据

场景&#xff1a;iPhone使用多年&#xff08;穷没钱换新的&#xff09;照片视频一直没有删除&#xff0c;最近打开微信提示空间不足&#xff0c;删除100多G照片后&#xff0c;照片应用程序的文稿与数据仍然100G没有变化。 不想重置手机&#xff0c;处理方法如下&#xff0c;PC端…

.netcore发布独立版部署

.NetCore 在发布独立版时会打包独立环境&#xff0c;就算服务没有安装环境也能运行&#xff0c;这就是.NetCore跨平台的特性之一。 按照微软的传统配套&#xff0c;c#开发的项目一般都是发布打包程序部署在iis&#xff0c;但是.netcore 跨平台的&#xff0c;就是说当发布独立版…

全栈之前端 | 2.CSS3基础知识之选择器学习

关注回复【学习交流群】加入【安全开发运维】答疑交流群 请朋友们【多多点击文中的广告】&#xff0c;支持作者更新更多文章。 目录: 0x00 前言简述 Q: 选择器是什么&#xff1f; 你也许已经见过选择器了。CSS 选择器是 CSS 规则的第一部分。它是元素和其他部分组合起来告诉浏览…

Sping源码(七)— 后置处理器(自定义后置处理器)

上一篇中简单介绍了Spring中invokeBeanFactoryPostProcessors方法的执行流程&#xff0c;以及BFPP和BDRPP类的介绍&#xff0c;这篇文章我们来自定义实现一个类的后置处理器。 自定义PostProcessor 自定义PostProcessor的方式一共两种&#xff0c;都是根据invokeBeanFactoryPo…

SM2(国密)非对称(公钥私钥)在线加密解密

SM2(国密)非对称(公钥私钥)在线加密/解密/生成密钥对

【mq】如何保证消息可靠性

文章目录 mq由哪几部分组成rocketmqkafka 为什么需要这几部分nameserver/zookeeper可靠性 broker可靠性 生产者消费者 mq由哪几部分组成 rocketmq kafka 这里先不讨论Kafka Raft模式 比较一下&#xff0c;kafka的结构和rocketmq的机构基本上一样&#xff0c;都需要一个注册…

2023 江苏省研究生数学建模 A 题思路

2023年江苏省研究生数学建模科研创新实践大赛A题新型抗癌药物研究模型探索靶向治疗是治疗肿瘤疾病的一种重要方法&#xff0c;它具有针对性强、疗效显著等特点。现有的靶向药物通常针对特定的基因突变靶点&#xff0c;容易出现耐药性。目前&#xff0c;一种由癌症诱发的血管新生…

回归预测 | MATLAB实现CSO-ELM布谷鸟算法优化极限学习机多输入单输出回归预测(多指标,多图)

回归预测 | MATLAB实现CSO-ELM布谷鸟算法优化极限学习机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09; 目录 回归预测 | MATLAB实现CSO-ELM布谷鸟算法优化极限学习机多输入单输出回归预测&#xff08;多指标&#xff0c;多图&#xff09;效果一览基本介…

Go 使用 Gorm 将操作信息集成到链路跟踪 Jaeger,进行增删改查使用举例,并做可视化UI界面展示(附源码)

Go 使用 Gorm 将操作信息集成到链路跟踪 Jaeger,进行增删改查使用举例(附源码)。 为了增强程序的可观测性,方便问题定位,在发起数据库操作请求时我们也可以调用代码统一集成链路跟踪的能力,Jaeger 是当今比较流行的选择。使用 Gorm 来将操作信息集成到 Jaeger 中。 全面…

Gazebo GPU加速【gzserver running in GPU】

文章目录 Gazebo GPU加速1. 问题2. 解决办法2.1 本机运行 2.2 headless3. 补充3.1 如何确定的Gazebo为OpenGL渲染3.2 显卡驱动--no-opengl-files3.3 nouveau Gazebo GPU加速 1. 问题 Gazebo仿真帧率极低&#xff0c;fps在10以下&#xff0c;同时显卡驱动已安装&#xff0c;但…

WebRTC之FEC前向纠错协议

FEC前向纠错用于丢包恢复&#xff0c;对媒体包进行异或或其他算法生成冗余包进行发送。如果接收端出现丢包&#xff0c;可以通过冗余包恢复出原始的媒体包。FEC的代价是增加码率带宽&#xff0c;所以一般会根据网络状况、丢包率来动态调整FEC冗余系数&#xff0c;也会结合NACK/…

mtk8175添加一款camera(GC5035)流程

说明&#xff1a; 在MTK平台添加一款新的Camera IC 需要如下三个步骤&#xff1a; device目录下面添加相关宏定义。 kernel目录下面添加dts配置&#xff0c;即硬件管脚、时钟、电源、I2C等的配置和 添加相关的驱动。 vendor 目录下面添加相关的效果文件。 下面是自己在MTK…

在Java8的forEach()中使用break/continue

今天在开发中&#xff0c;使用forEach()来遍历元素执行业务操作&#xff0c;发现如果判断不符合某个条件时就要continue&#xff0c;不能继续向后执行了。但是在forEach()中不能使用for循环中的continue和break&#xff0c;那改如何退出呢&#xff1f; 答案是&#xff1a;使用…

利用open_cv在图像上进行点标记,文字注记,画圆、多边形、椭圆

&#xff08;1&#xff09;CV2中的绘图函数&#xff1a; cv2.line() 绘制线条cv2.circle() 绘制圆cv2.rectangle() 绘制矩形cv2.ellipse() 绘制椭圆cv2.putText() 添加注记 &#xff08;2&#xff09;注释 img表示需要绘制的图像color表示线条的颜色&#xff0c;采用颜色矩阵…

Python基础学习第一天:关于Python的简单介绍

前言 最近一批批大一新生都要开始踏入校园了&#xff0c;计算机专业 emmm…如果有需要学习python的&#xff0c;尤其是还没开学的&#xff0c;确实可以开始找找资料看看python了&#xff0c;如果是自己本来就对python感兴趣&#xff0c;更应该需要看看了&#xff0c;毕竟学校到…

【五】sql 语言 -- 概览

SQL 语言概述SQL 语言提出和发展SQL 语言的功能概述利用 SQL 语言建立数据库学生选课数据库 SCT1. 定义数据库和表 SQL-DDL创建数据库的语句—Create Database创建关系/表的语句—Create Table 2. 向表中追加元组 SQL-DML 利用 SQL 语言进行简单查询单表查询 - SELECT-FROM-WHE…

工地安全帽识别闸机联动开关 yolov7

工地安全帽识别闸机联动开关系统通过yolov7系列网络模型深度学习算法&#xff0c;工地安全帽识别闸机联动开关算法对施工人员的人脸、安全帽和反光衣进行识别&#xff0c;判断是否符合安全要求。只有当人脸识别成功且安全帽、反光衣齐全时&#xff0c;闸机才会打开允许施工人员…

FFmpeg支持多线程编码并保存mp4文件示例

之前介绍的示例&#xff1a; (1).https://blog.csdn.net/fengbingchun/article/details/132129988 中对编码后数据保存成mp4 (2).https://blog.csdn.net/fengbingchun/article/details/132128885 中通过AVIOContext实现从内存读取数据 (3).https://blog.csdn.net/fengbingchun/…

基于XGBoots预测A股大盘《上证指数》(代码+数据+一键可运行)

对AI炒股感兴趣的小伙伴可加WX&#xff1a;caihaihua057200&#xff08;备注&#xff1a;学校/公司名字方向&#xff09; 另外我还有些AI的应用可以一起研究&#xff08;我一直开源代码&#xff09; 1、引言 在这期内容中&#xff0c;我们回到AI预测股票&#xff0c;转而探索…