LeetCode—538. 把二叉搜索树转换为累加树(Convert BST to Greater Tree)——分析及代码(Java)

一、题目

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

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

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

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

示例 1:

输入:[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]

提示:

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

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/convert-bst-to-greater-tree
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

二、分析及代码

1. 反向中序遍历

(1)思路

结合二叉搜索树的特点,从右至左反向进行中序遍历的同时累加,即可将其转换为所需的累加树。

(2)代码(迭代)

import java.util.Stack;

class Solution {
    
    
    public TreeNode convertBST(TreeNode root) {
    
    
        if (root == null)
            return root;
        
        int sum = 0;
        Stack<TreeNode> sta = new Stack<>();
        sta.push(root);
        while (!sta.empty()) {
    
    
            TreeNode node = sta.pop();
            while (node.right != null) {
    
    
                sta.push(node);
                node = node.right;
            }
            while (!sta.empty() && node.left == null) {
    
    
                node.val += sum;
                sum = node.val;
                node = sta.pop();
            }
            node.val += sum;
            sum = node.val;
            if (node.left != null)
                sta.push(node.left);     
        }

        return root;        
    }
}

(3)结果(迭代)

执行用时 :2 ms, 在所有 Java 提交中击败了 14.93% 的用户;
内存消耗 :39 MB, 在所有 Java 提交中击败了 42.05% 的用户。

(4)代码(递归)

import java.util.Stack;

class Solution {
    
    
    int sum = 0;

    public TreeNode convertBST(TreeNode root) {
    
    
        if (root == null)
            return root;
            
        convertBST(root.right);
        root.val += sum;
        sum = root.val;
        convertBST(root.left);

        return root;        
    }
}

(5)结果(递归)

执行用时 :1 ms, 在所有 Java 提交中击败了 97.46% 的用户;
内存消耗 :38.9 MB, 在所有 Java 提交中击败了 80.46% 的用户。

2. Morris 遍历

(1)思路

可结合 Morris 方法,对遍历过程进一步优化,通过利用树中的空闲指针,在常数空间和线性时间内完成遍历,其过程为:

  • 若右节点为空,处理当前节点,并跳转到其左节点;
  • 若右节点的最左子节点的左节点为空,将最左子节点的左节点设置为当前节点,并跳转到其右节点;
  • 若右节点的最左子节点的左节点为当前节点,将最左子节点的左节点设置为空,处理当前节点,并跳转到其左节点。

(2)代码

class Solution {
    
    
    public TreeNode convertBST(TreeNode root) {
    
    
        int sum = 0;
        TreeNode node = root;
        while (node != null) {
    
    
            if (node.right == null) {
    
    
                node.val += sum;
                sum = node.val;
                node = node.left;
            } else {
    
    
                TreeNode succ = getSucc(node);
                if (succ.left  == null) {
    
    
                    succ.left = node;
                    node = node.right;
                } else {
    
    
                    succ.left = null;
                    node.val += sum;
                    sum = node.val;
                    node= node.left;
                }
            }
        }
        return root;
    }

    private TreeNode getSucc(TreeNode node) {
    
    
        TreeNode succ = node.right;
        while (succ.left != null && succ.left != node)
            succ = succ.left;
        return succ;
    }
}

(3)结果

执行用时 :1 ms, 在所有 Java 提交中击败了 96.43% 的用户;
内存消耗 :38.7 MB, 在所有 Java 提交中击败了 92.72% 的用户。

三、其他

暂无。

猜你喜欢

转载自blog.csdn.net/zml66666/article/details/112795991