LeetCode 1038.从二叉搜索树到更大和树

给定一个二叉搜索树 root (BST),请将它的每个节点的值替换成树中大于或者等于该节点值的所有节点值之和。

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

节点的左子树仅包含键 小于 节点键的节点。

节点的右子树仅包含键 大于 节点键的节点。

左右子树也必须是二叉搜索树。

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

提示:

树中的节点数在 [1, 100] 范围内。

0 <= Node.val <= 100

树中的所有值均 不重复 。

法一:反向中序遍历即可,用一个变量记录累加和,以下是递归遍历:

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* bstToGst(TreeNode* root) {
        int sum = 0;
        reverseInorderTraversal(root, sum);

        return root;
    }

private:
    void reverseInorderTraversal(TreeNode *node, int &sum)
    {
        if (node == nullptr)
        {
            return;
        }

        reverseInorderTraversal(node->right, sum);
        sum += node->val;
        node->val = sum;
        reverseInorderTraversal(node->left, sum);
    }
};

如果树中有n个节点,此算法时间复杂度为O(n),空间复杂度为树的高度O(logn)(平均情况,最差情况为O(n))。

法二:法一的迭代版:

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* bstToGst(TreeNode* root) {
        stack<TreeNode *> s;
        int sum = 0;
        TreeNode *cur = root;
        while (cur || !s.empty())
        {
            while (cur)
            {
                s.push(cur);
                cur = cur->right;
            }
            cur = s.top();
            s.pop();

            sum += cur->val;
            cur->val = sum;

            cur = cur->left;
        }

        return root;
    }
};

如果树中有n个节点,此算法时间复杂度为O(n),空间复杂度为树的高度O(logn)(平均情况,最差情况为O(n))。

法三:Morris遍历,要点在于找到当前节点的前驱节点,对于反向中序遍历,某节点的前驱节点是右子树的最左节点:

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* bstToGst(TreeNode* root) {
        int sum = 0;
        TreeNode *cur = root;
        while (cur)
        {
            if (!cur->right)
            {
                sum += cur->val;
                cur->val = sum;

                cur = cur->left;
                continue;
            }

            TreeNode *leftestOfRight = getLeftestOfRight(cur);
            if (leftestOfRight->left)
            {
                sum += cur->val;
                cur->val = sum;

                leftestOfRight->left = nullptr;
                cur = cur->left;
            }
            else
            {
                leftestOfRight->left = cur;
                cur = cur->right;
            }
        }

        return root;
    }

private:
    TreeNode *getLeftestOfRight(TreeNode *node)
    {
        TreeNode *cur = node->right;
        while (cur->left && cur->left != node)
        {
            cur = cur->left;
        }

        return cur;
    }
};

如果树中有n个节点,此算法时间复杂度为O(n),空间复杂度为O(1)。

法四:由于输入的是二叉搜索树,因此我们可以每次找到比当前值小的前一个节点,依次更新:

cpp 复制代码
/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* bstToGst(TreeNode* root) {
        TreeNode *curTarget = getMax(root);
        int sum = 0;
        int lastNum = curTarget->val;
        while (curTarget)
        {
            lastNum = curTarget->val;
            sum += curTarget->val;
            curTarget->val = sum;

            curTarget = getLess(root, lastNum);
        }

        return root;
    }

private:
    TreeNode *getMax(TreeNode *node)
    {
        while (node->right)
        {
            node = node->right;
        }

        return node;
    }

    TreeNode *getLess(TreeNode *root, int target)
    {
        TreeNode *lessTarget = nullptr;
        while (root)
        {
            if (root->val > target)
            {
                root = root->left;
            }
            else if (root->val < target)
            {
                if (!lessTarget || root->val > lessTarget->val)
                {
                    lessTarget = root;
                }
                root = root->right;
            }
            else
            {
                break;
            }
        }

        return lessTarget;
    }
};

如果树中有n个节点,此算法时间复杂度为O(nlgn),空间复杂度为O(1)。

相关推荐
fancy16616623 分钟前
搜索二维矩阵 II
c++·算法·矩阵
freyazzr24 分钟前
Leetcode刷题 | Day63_图论08_拓扑排序
数据结构·c++·算法·leetcode·图论
暴龙胡乱写博客29 分钟前
机器学习 --- KNN算法
人工智能·算法·机器学习
ai.Neo1 小时前
牛客网NC22015:最大值和最小值
数据结构·c++·算法
是麟渊1 小时前
【大模型面试每日一题】Day 17:解释MoE(Mixture of Experts)架构如何实现模型稀疏性,并分析其训练难点
人工智能·自然语言处理·面试·职场和发展·架构
Swift社区2 小时前
LeetCode 高频题实战:如何优雅地序列化和反序列化字符串数组?
算法·leetcode·职场和发展
徐子童2 小时前
《从零开始入门递归算法:搜索与回溯的核心思想 + 剑指Offer+leetcode高频面试题实战(含可视化图解)》
算法
天宫风子3 小时前
抽象代数小述(二之前)
经验分享·笔记·算法·生活·抽象代数
向上的车轮3 小时前
“傅里叶变换算法”来检测纸箱变形的简单示例
算法
九亿AI算法优化工作室&3 小时前
乡村地区无人机医药配送路径规划与优化仿真
人工智能·算法·matlab·回归