ShuangChenYue ShuangChenYue
首页
  • Cpp之旅
  • Cpp专栏
  • Effective_CPP
  • muduo网络库
  • Unix环境高级编程
  • Cpp提高编程
  • 计算机网络
  • 操作系统
  • 数据结构
  • Linux
  • 算法
  • 基础篇
  • MySql
  • Redis
  • 电子嵌入式通信协议
  • 深入浅出SSD
  • 文件系统
  • 汇编语言
  • STM32
  • 随笔(持续更新)
  • Git知识总结
  • Git 创建删除远程分支
  • nvm使用小结
  • 虚拟机固定 IP 地址
  • Shell 脚本学习笔记
  • VScode 插件 CodeGeeX 使用教程
  • KylinV10 将项目上传至 Github教程
  • KylinV10 安装 MySQL 教程(可防踩雷)
  • kylinV10-SP1 安装 QT
  • 高并发内存池
  • USBGUARD 项目编译环境配置
  • Power_Destory 项目
  • U 盘清除工具编译教程
  • 个人博客代码推送教程
  • HTML与CSS
  • JS学习
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • MFC编程随记
  • MFC实现ini配置文件的读取
  • MFC实现点击列表头排序
  • 贴图法美化Button按钮
  • 如何高效阅读嵌入式项目代码
  • NAND Flash
  • ARM 处理器
  • 嵌入式基础知识-存储器
  • 闪存存储和制造技术概述
  • 芯片IO驱动力
  • 主流先进封装技术介绍
  • 虎牙C++技术面经
  • 金山一面复习
  • 完美世界秋招 C++ 游戏开发面经(Cpp部分)
  • 博客搭建
  • 网站收藏箱
首页
  • Cpp之旅
  • Cpp专栏
  • Effective_CPP
  • muduo网络库
  • Unix环境高级编程
  • Cpp提高编程
  • 计算机网络
  • 操作系统
  • 数据结构
  • Linux
  • 算法
  • 基础篇
  • MySql
  • Redis
  • 电子嵌入式通信协议
  • 深入浅出SSD
  • 文件系统
  • 汇编语言
  • STM32
  • 随笔(持续更新)
  • Git知识总结
  • Git 创建删除远程分支
  • nvm使用小结
  • 虚拟机固定 IP 地址
  • Shell 脚本学习笔记
  • VScode 插件 CodeGeeX 使用教程
  • KylinV10 将项目上传至 Github教程
  • KylinV10 安装 MySQL 教程(可防踩雷)
  • kylinV10-SP1 安装 QT
  • 高并发内存池
  • USBGUARD 项目编译环境配置
  • Power_Destory 项目
  • U 盘清除工具编译教程
  • 个人博客代码推送教程
  • HTML与CSS
  • JS学习
  • Vue3入门
  • Vue3进阶
  • 黑马Vue3
  • MFC编程随记
  • MFC实现ini配置文件的读取
  • MFC实现点击列表头排序
  • 贴图法美化Button按钮
  • 如何高效阅读嵌入式项目代码
  • NAND Flash
  • ARM 处理器
  • 嵌入式基础知识-存储器
  • 闪存存储和制造技术概述
  • 芯片IO驱动力
  • 主流先进封装技术介绍
  • 虎牙C++技术面经
  • 金山一面复习
  • 完美世界秋招 C++ 游戏开发面经(Cpp部分)
  • 博客搭建
  • 网站收藏箱
  • 网络

  • 操作系统

  • 数据结构

  • 算法

    • 两数之和
    • 回文数
    • 最长公共前缀
    • 三数之和
    • 删除有序数组中的重复项
    • 最大子数组和
    • x 的平方根
    • 爬楼梯
    • 对称二叉树
    • 二叉树的最大深度
    • LCR寻找文件副本
    • 买卖股票的最佳时机
    • LCR图书整理 II
    • 只出现一次的数字
    • LCR 训练计划 II
    • 环形链表
    • LRU 缓存
    • 反转字符串中的单词
    • LCR 破冰游戏
    • 反转链表
    • 翻转二叉树
    • 回文链表
    • 移动零
    • 最长回文串
    • 汉明距离
    • 把二叉搜索树转换为累加树
      • 题目:
      • 示例:
      • 题目解释:
      • 解题:
        • 方法一:反序中序遍历
        • 方法二:Morris 遍历
    • 最短无序连续子数组
    • 合并二叉树
    • 二分查找
    • 链表的中间结点
    • 有序数组的平方
    • 找到小镇的法官
  • Linux

  • 计算机基础
  • 算法
霜晨月
2023-12-01
目录

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

# 538. 把二叉搜索树转换为累加树 (opens new window)

# 题目:

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

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

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

注意: 本题和 1038: https://leetcode-cn.com/problems/binary-search-tree-to-greater-sum-tree/ 相同

# 示例:

示例 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]
1
2

# 题目解释:

是不是没读懂题目?没关系,举个例子你就明白了:

比如说根节点4转换为累加树之后为什么新值是30?按题目中的意思就是大于等于根节点4的原来二叉树的值全部加起来,即根节点4+(它的右子树)= 4 + 6 + 5 + 7 + 8 = 30,同理根节点4的左孩子节点1,那就是要将大于等于1的原二叉树的值全部加起来,那就是从自身开始1 + 2 + 3 + (之前根节点4累加的值,因为它们都比1大) = 36,所以新值为36,依此类推。

这样子看来,题目是读懂了,但是没啥规律啊?解不了题啊?

根据题目的提示会发现原二叉树是满足以下性质的:

  1. 若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
  2. 若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
  3. 它的左、右子树也分别为二叉搜索树。

说明原二叉树就是二叉搜索树,而累加树则刚好与二叉搜索树性质相反,刚好二叉搜索树的中序遍历是一个单调递增的有序序列。那么是否意味着累加树的逆序中序遍历是一个单调递减的有序序列。

二叉搜索树的中序遍历:[0、1、2、3、4、5、6、7、8]

累加树的中序遍历:[36、36、35、33、30、26、24、15、8]

果然如此!

示例 2:

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

示例 3:

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

示例 4:

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

提示:

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

# 解题:

# 方法一:反序中序遍历

所以根据我的题目解释,这样我们只需要反序中序遍历该二叉搜索树,记录过程中的节点值之和,并不断更新当前遍历到的节点的节点值,即可得到题目要求的累加树。

class Solution {
public:
    int sum = 0;
    TreeNode* convertBST(TreeNode* root) {
        if(root != nullptr) {
            convertBST(root->right);
            sum += root->val;
            root->val = sum;
            convertBST(root->left);
        }
        return root;
    }
};
1
2
3
4
5
6
7
8
9
10
11
12
13

复杂度分析:

  • 时间复杂度:O(n),其中 n 是二叉搜索树的节点数。每一个节点恰好被遍历一次。

  • 空间复杂度:O(n),为递归过程中栈的开销,平均情况下为 O(log~⁡n~),最坏情况下树呈现链状,为 O(n)。

看不懂代码的可以去调试一下代码就懂了

#include <iostream>

// 二叉树节点定义
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

class Solution {
public:
    TreeNode* convertBST(TreeNode* root) {
        if(root != nullptr) {
            convertBST(root->right);
            sum += root->val;
            root->val = sum;
            convertBST(root->left);
        }
        return root;
    }

private:
    int sum = 0; // 成员变量用于记录累加值
};

// 中序遍历打印二叉树
void inOrderTraversal(TreeNode* root) {
    if (root) {
        inOrderTraversal(root->left);
        std::cout << root->val << " ";
        inOrderTraversal(root->right);
    }
}

int main() {
    // 示例用法
    // 创建一棵示例二叉搜索树
    TreeNode* root = new TreeNode(4);
    root->left = new TreeNode(1);
    root->right = new TreeNode(6);
    root->left->left = new TreeNode(0);
    root->left->right = new TreeNode(2);
    root->right->left = new TreeNode(5);
    root->right->right = new TreeNode(7);
    root->left->right->right = new TreeNode(3);
    root->right->right->right = new TreeNode(8);


    // 创建 Solution 对象
    Solution solution;

    // 转换为累加树(使用你提供的方式)
    TreeNode* greaterSumTree = solution.convertBST(root);

    // 打印累加树的中序遍历结果
    std::cout << "累加树的中序遍历结果: ";
    inOrderTraversal(greaterSumTree);
    std::cout << std::endl;

    return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

下面给出部分调试过程:

一开始先一直递归,直到右子树的末尾叶子节点8

1701054284398

1701054316584

然后递归里的执行:

1701054116346

1701054176037

1701054193305

# 方法二:Morris 遍历

这个方法不搞了,第一个理解透彻就挺累的了。有需要自己去看吧

538. 把二叉搜索树转换为累加树 - 力扣(LeetCode) (opens new window)

上次更新: 2024/6/3 14:54:44
汉明距离
最短无序连续子数组

← 汉明距离 最短无序连续子数组→

Theme by Vdoing | Copyright © 2023-2024 霜晨月
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式