Given the root
of a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original BST is changed to the original key plus the sum of all keys greater than the original key in BST.
As a reminder, a binary search tree is a tree that satisfies these constraints:
Example 1:
Input: root = [4,1,6,0,2,5,7,null,null,null,3,null,null,null,8] Output: [30,36,21,36,35,26,15,null,null,null,33,null,null,null,8]
Example 2:
Input: root = [0,null,1] Output: [1,null,1]
Constraints:
[1, 100]
.0 <= Node.val <= 100
Note: This question is the same as 538: https://leetcode.com/problems/convert-bst-to-greater-tree/
The problem asks to convert a Binary Search Tree (BST) into a Greater Sum Tree. In a Greater Sum Tree, each node's value is updated to be the sum of all nodes with values greater than or equal to its original value in the BST.
Both solutions presented leverage the property of BSTs: nodes in the right subtree are always greater than the current node. This allows for efficient traversal and summation.
This approach uses a recursive depth-first search to traverse the tree in reverse inorder traversal (right, root, left). This order ensures that we process nodes with greater values before smaller values, allowing us to accumulate the sum correctly.
Algorithm:
dfs(root)
function: This recursive function performs the following steps:
dfs
on the right subtree to process larger values first.root.val
) to the running sum (s
).s
).dfs
on the left subtree.Main Function:
s
to 0.dfs(root)
to start the traversal.root
.Time Complexity: O(N), where N is the number of nodes in the BST. We visit each node exactly once.
Space Complexity: O(H), where H is the height of the BST. This is due to the recursive call stack. In the worst case (a skewed tree), H could be N, resulting in O(N) space complexity. In a balanced BST, H is log₂N.
This approach utilizes the Morris traversal algorithm, an in-place algorithm that avoids recursion and uses constant extra space. It cleverly uses the left subtree to maintain the inorder traversal order without needing an explicit stack.
Algorithm:
Initialization:
s
is initialized to 0 (the running sum).node
is set to the root
.Iteration: The while
loop continues as long as there is a node to process:
root.right
is None): This means we've reached the rightmost node of a subtree. We add the node's value to s
, update the node's value to s
, and move to the left child.root.right
is not None): We find the inorder predecessor (the rightmost node in the left subtree) to link the current node to its inorder successor. This is done efficiently by traversing the right subtree until the leftmost node without a left child. If the predecessor's left child is not the current node (it's NULL), we link the predecessor's left child to the current node and move to the right subtree. If it already points to the current node (it's not NULL), we've already processed the right subtree, so we perform the sum update and move to the left subtree, resetting the link.Return: The modified root
node.
Time Complexity: O(N). Each node is visited and processed exactly once.
Space Complexity: O(1). The algorithm is in-place and uses only a constant amount of extra space.
In summary, Solution 1 is simpler to understand but may use more space for deep trees, while Solution 2 is more optimized in terms of space complexity but slightly more complex to grasp. Both solutions offer correct and efficient solutions to the problem.