题目描述

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

image-20260928224306931

image-20260928224306932

image-20260928224306933

题意分析

将二叉搜索树中每个节点的值,替换为它的原值加上所有比它大的节点原值之和。只修改数值,原有左右连接保持不变,返回的仍是原根节点。

每个节点需要的不是某棵局部子树的和,而是整棵树中全部更大原值的和。利用 BST 的有序关系,按从大到小的顺序处理,就能让一个累计变量提供所有节点所需的结果。

解法:反向中序遍历累加

核心思路

[!blue]

普通中序按左、根、右访问 BST,得到从小到大的顺序;反过来按右、根、左访问,就会先处理全部更大的节点,再处理当前节点,最后处理更小的节点。

用共享变量 sum 累加已经访问过的原始值。访问当前节点之前,它恰好包含所有严格大于当前原值的节点;先执行 sum += node.val,再把 sum 写回当前节点,就得到题目要求的新值。

累加必须发生在覆盖之前。尚未访问的节点仍保存原值,已访问节点即使已经改写,它的原值也已经计入 sum,不会再重复读取。后续遍历只沿原来的树结构进行,不根据修改后的值重新判断大小,因此改值不会破坏访问顺序。

累计变量要贯穿整次遍历。进入左子树时,它还需要包含父节点以及此前访问过的其他较大节点,不能在每层递归重新清零。Java 在入口重置成员变量,Go 在每次函数调用内创建变量,保证不同调用不会混用旧累计值。

空节点直接结束,非空节点按右、根、左顺序完成上述操作。输入存在负值时,累计和可能减小,但只要访问顺序按原值从大到小,累计结果仍然正确,不依赖和本身单调增加。

解题步骤

  1. 每次入口将累计值 sum 初始化为零。
  2. 递归遇到空节点直接返回,否则先处理右子树。
  3. 将当前节点原值加入 sum,再令节点值等于 sum。
  4. 继续处理左子树,让更小的节点复用已经累加的所有较大值。
  5. 全树处理完后返回原根节点。

代码实现

class Solution {
    private int sum;

    public TreeNode convertBST(TreeNode root) {
        // 每次入口重新累计,避免复用对象时混入旧结果
        sum = 0;
        dfs(root);

        return root;
    }

    private void dfs(TreeNode node) {
        if (node == null) {
            return;
        }

        // 先访问所有更大的原值,再处理当前节点
        dfs(node.right);

        // sum 保存所有已经访问过的更大节点之和。
        sum += node.val;
        node.val = sum;

        dfs(node.left);
    }
}
func convertBST(root *TreeNode) *TreeNode {
    sum := 0

    var dfs func(node *TreeNode)
    dfs = func(node *TreeNode) {
        if node == nil {
            return
        }

        // 先访问所有更大的原值,再处理当前节点
        dfs(node.Right)

        // sum 保存所有已经访问过的更大节点之和。
        sum += node.Val
        node.Val = sum

        dfs(node.Left)
    }

    dfs(root)
    return root
}

复杂度分析

  • 时间复杂度:$O(n)$,每个节点一次累加与赋值。
  • 空间复杂度:$O(h)$,递归栈与树高同阶。

关键点总结

[!green]

  • 当前值加严格更大值之和,才等于大于等于当前值的总和。
  • 输入可以含负值,累计和不要求单调。

易错点总结

[!yellow]

  • 普通中序累加得到更小值之和,方向相反。
  • 先赋值再累加会读到被覆盖的数,丢失原值。
  • 每层递归重新清零,会破坏整棵树共享的后缀累计。

相似题目

题目 难度 关联与区别
230. 二叉搜索树中第 K 小的元素 中等 都利用BST中序有序性,本题改用逆中序累计更大值,原题按升序定位第k项。
897. 递增顺序搜索树 简单 同样通过有序遍历改造BST,原题改连接而保留节点值,本题改值并保留连接。
转载与许可
作者
链接 https://hgnulb.github.io/blog/2024/08310769
许可 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议,转载请注明出处!