LeetCode 538.把二叉搜索树转换为累加树
1、题目
题目链接:538. 把二叉搜索树转换为累加树
给出二叉 搜索 树的根节点,该树的节点值各不相同,请你将其转换为累加树(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 之间。
- 树中的所有值 互不相同 。
- 给定的树为二叉搜索树。
2、递归法(反向中序遍历)
思路
二叉搜索树是一棵空树,或者是具有下列性质的二叉树:
若它的左子树不空,则左子树上所有节点的值均小于它的根节点的值;
若它的右子树不空,则右子树上所有节点的值均大于它的根节点的值;
它的左、右子树也分别为二叉搜索树。
由这样的性质我们可以发现,二叉搜索树的中序遍历是一个单调递增的有序序列。如果我们反序地中序遍历该二叉搜索树,即可得到一个单调递减的有序序列。
本题中要求我们将每个节点的值修改为原来的节点值加上所有大于它的节点值之和。这样我们只需要反序中序遍历该二叉搜索树,记录过程中的节点值之和,并不断更新当前遍历到的节点的节点值,即可得到题目要求的累加树。
代码
class Solution {
public:
// 用来记录前一个节点的值
int pre = 0;
TreeNode* convertBST(TreeNode* root) {
if (root != nullptr) {
// 递归遍历右子树
convertBST(root->right);
// 将当前节点的值加上pre,实现累加效果
root->val += pre;
// 更新pre的值为当前节点的值
pre = root->val;
// 递归遍历左子树
convertBST(root->left);
}
return root;
}
};
复杂度分析
- 时间复杂度: O(n)
- 空间复杂度: O(n)
3、迭代法(反向中序遍历)
思路
用迭代法反向中序遍历该二叉搜索树,记录过程中的节点值之和,并不断更新当前遍历到的节点的节点值,即可得到题目要求的累加树。
具体步骤如下:
- 初始化:
- 创建一个栈 stk 用于辅助遍历。
- 创建一个指针 cur 指向根节点 root。
- 定义一个全局变量 pre,用于记录前一个节点的值,初始化为0。这个变量会在遍历过程中持续更新,以确保当前节点能够正确累加上前一个节点的值。
- 遍历过程:
- 使用一个循环,其条件是 cur 不为空或者栈 stk 不为空。这确保了整棵树都会被遍历完。
- 在循环内部,首先处理当前节点的右子树。如果 cur 不为空,就将其压入栈中,并将 cur 更新为其右子节点。这样做是因为在中序遍历中,当前节点的右子树会在处理当前节点之前被先处理。
- 当 cur 为空时,意味着已经到达了某个子树的最右端,此时从栈顶弹出一个节点,并更新该节点的值。将 pre(前一个节点的值)加到当前节点的值上,实现累加效果。然后,更新 pre 为当前节点的值。
- 接下来,处理当前节点的左子树。将 cur 更新为当前节点的左子节点,进入下一轮循环。由于栈的后进先出特性,这会保证在后续迭代中,当前节点的左子树会被优先处理。
- 返回结果:
- 当整个循环结束时,所有的节点都已经按照中序遍历的顺序被处理过,并且每个节点的值都被更新为了从根节点到该节点路径上所有节点值的累加和。最后,返回根节点 root,此时整棵树已经被转换为了累加树。
代码
class Solution {
public:
// 用来记录前一个节点的值
int pre = 0;
TreeNode* convertBST(TreeNode* root) {
stack<TreeNode*> stk;
TreeNode* cur = root;
while (cur != nullptr || !stk.empty()) {
// 先处理右子树
if (cur != nullptr) {
stk.push(cur);
cur = cur->right;
} else {
// 处理当前节点
cur = stk.top();
stk.pop();
// 将当前节点的值加上之前的值
cur->val += pre;
// 将当前节点的值赋值给pre
pre = cur->val;
// 处理左子树
cur = cur->left;
}
}
return root;
}
};
复杂度分析
- 时间复杂度: O(n)
- 空间复杂度: O(n)