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

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

题目:

给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(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]

题目解释:

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

比如说根节点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]

示例 3:

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

示例 4:

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

提示:

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

解题:

方法一:反序中序遍历

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

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;
    }
};

复杂度分析:

  • 时间复杂度: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;
}

下面给出部分调试过程:

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

在这里插入图片描述
在这里插入图片描述

然后递归里的执行:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

方法二:Morris 遍历

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

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

  • 22
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

霜晨月c

谢谢老板地打赏~

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值