0%

『LeetCode』538 把二叉搜索树转换为累加树

题目

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\)\(10^{4}\) 之间。
  • 每个节点的值介于 \(-10^{4}\)\(10^{4}\) 之间。
  • 树中的所有值 互不相同
  • 给定的树为二叉搜索树。

标签

树, 深度优先搜索, 二叉搜索树, 二叉树


题解

【把二叉搜索树转换为累加树】递归&迭代遍历

递归

题目的难度还是理解题意,可以换个思路:给出一个有序数组 [1,2,3,4,5],需要将每个位置的值替换为大于等于该位置值的数字,显然由于数组有序,那么其实就是求一个后缀和数组,即 [15,14,12,9,5],这很容易,从后向前累加即可

回到题目,其实题目的意义和上面的后缀数组意思是一样的,只是数组换成了二叉搜索树,但二叉搜索树的中序遍历不就是一个有序集合吗?所以思路是一致的:

我们只需逆着中序遍历二叉树,将结果累加即可。具体来说:中序遍历的顺序是:左子树,根节点,右子树。其逆序即为:右子树,根节点,左子树。使用递归是个很容易的选择。

1
2
3
4
5
6
7
8
9
10
11
12
# Code language: Python
class Solution:
def __init__(self):
self.s = 0

def convertBST(self, root: TreeNode) -> TreeNode:
if root:
self.convertBST(root.right)
self.s += root.val
root.val = self.s
self.convertBST(root.left)
return root
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Code language: Java
class Solution {
public int sum = 0;

public TreeNode convertBST(TreeNode root) {
if (root != null) {
convertBST(root.right);
sum += root.val;
root.val = sum;
convertBST(root.left);
}
return root;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// Code language: C++
class Solution {
public:
int s = 0;
TreeNode* convertBST(TreeNode* root) {
if (root != nullptr){
convertBST(root->right);
s += root->val;
root->val = s;
convertBST(root->left);
}
return root;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// Code language: Go
func convertBST(root *TreeNode) *TreeNode {
dfs(root, 0)
return root
}

func dfs(root *TreeNode, v int) int {
if root == nil {
return v
}
r := dfs(root.Right, v)
root.Val += r
l := dfs(root.Left, root.Val)
return l
}
  • 时间复杂度: \(O(n)\), 将树中结点数量记为 \(n\), 需要每个结点遍历一次
  • 空间复杂度: \(O(n)\), 递归栈开销

迭代

递归可以转化为显式的栈来实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
# Code language: Python
class Solution:
def convertBST(self, root: TreeNode) -> TreeNode:
cur = root
s = 0
stack = []
while cur:
stack.append(cur)
cur = cur.right
while stack:
cur = stack.pop()
s += cur.val
cur.val = s
cur = cur.left
while cur:
stack.append(cur)
cur = cur.right
return root
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Code language: Java
class Solution {
public TreeNode convertBST(TreeNode root) {
TreeNode cur;
int sum = 0;
Stack<TreeNode> s = new Stack<TreeNode>();
for (cur = root; cur != null; cur = cur.right)
s.add(cur);
while (!s.empty()){
cur = s.pop();
sum += cur.val;
cur.val = sum;
for (cur = cur.left; cur != null; cur = cur.right)
s.add(cur);
}
return root;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// Code language: C++
class Solution {
public:
TreeNode* convertBST(TreeNode* root) {
TreeNode* cur;
int sum = 0;
stack<TreeNode*> s;
for (cur = root; cur != nullptr; cur = cur->right)
s.emplace(cur);
while (!s.empty()){
cur = s.top();
s.pop();
sum += cur->val;
cur->val = sum;
for (cur = cur->left; cur != nullptr; cur = cur->right)
s.emplace(cur);
}
return root;
}
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// Code language: Go
func convertBST(root *TreeNode) *TreeNode {
var s = 0
var st []*TreeNode
for cur := root; cur != nil; cur = cur.Right {
st = append(st, cur)
}
for len(st) > 0 {
cur := st[len(st)-1]
st = st[:len(st)-1]
s += cur.Val
cur.Val = s
for cur = cur.Left; cur != nil; cur = cur.Right {
st = append(st, cur)
}
}
return root
}
  • 时间复杂度: \(O(n)\), 将树中结点数量记为 \(n\), 需要每个结点遍历一次
  • 空间复杂度: \(O(n)\), 栈开销

如果对你有帮助的话,请给我点个赞吧~

欢迎前往 我的博客Algorithm - Github 查看更多题解

--- ♥ end ♥ ---

欢迎关注我呀~