title: Convert BST to Greater Tree
slug: convert-bst-to-greater-tree
difficulty: medium
leetcode_id: 538
leetcode_url: https://leetcode.com/problems/convert-bst-to-greater-tree/
categories:
  - trees
patterns:
  - dfs
  - tree-traversal

function_signature: "def convert_bst(root: TreeNode | None) -> TreeNode | None:"

test_cases:
  visible:
    - input: { root: [4, 1, 6, 0, 2, 5, 7, null, null, null, 3, null, null, null, 8] }
      expected: [30, 36, 21, 36, 35, 26, 15, null, null, null, 33, null, null, null, 8]
    - input: { root: [0, null, 1] }
      expected: [1, null, 1]
  hidden:
    - input: { root: [] }
      expected: []
    - input: { root: [5] }
      expected: [5]
    - input: { root: [2, 1, 3] }
      expected: [5, 6, 3]
    - input: { root: [5, 3, 8, 1, 4, 6, 9] }
      expected: [33, 37, 17, 38, 34, 23, 9]
    - input: { root: [1, null, 2, null, 3, null, 4] }
      expected: [10, null, 9, null, 7, null, 4]
    - input: { root: [-3, -4, -2] }
      expected: [-5, -9, -2]

description: |
  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:

  - The left subtree of a node contains only nodes with keys **less than** the node's key.
  - The right subtree of a node contains only nodes with keys **greater than** the node's key.
  - Both the left and right subtrees must also be binary search trees.

constraints: |
  - `0 <= number of nodes <= 10^4`
  - `-10^4 <= Node.val <= 10^4`
  - All the values in the tree are **unique**
  - `root` is guaranteed to be a valid binary search tree

examples:
  - 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]"
    explanation: "Each node's new value equals its original value plus the sum of all nodes with greater values. For example, node 4 becomes 4 + 5 + 6 + 7 + 8 = 30."
  - input: "root = [0,null,1]"
    output: "[1,null,1]"
    explanation: "Node 1 stays 1 (no greater values). Node 0 becomes 0 + 1 = 1."

explanation:
  intuition: |
    Imagine you have a sorted list of numbers and you want to replace each number with the sum of itself and all numbers greater than it. You would naturally start from the **largest number** and work backwards, keeping a running total.

    The key insight is that a BST has a built-in sorted order: an **in-order traversal** (left → node → right) visits nodes in ascending order. But we need descending order to accumulate sums from largest to smallest.

    The solution is beautifully simple: use a **reverse in-order traversal** (right → node → left). This visits nodes from largest to smallest. As we traverse, we maintain a running sum of all values seen so far. Each node's new value becomes this running sum (which includes its original value plus all greater values).

    Think of it like this: you're walking through the tree in reverse sorted order, carrying a "cumulative total" that grows with each node you visit. When you reach a node, you add its value to your total, then update the node with this new total.

  approach: |
    We solve this using **Reverse In-Order Traversal** with a running sum:

    **Step 1: Understand the traversal order**

    - Standard in-order (left → node → right) gives ascending order
    - Reverse in-order (right → node → left) gives **descending order**
    - We need descending order to accumulate sums correctly

    &nbsp;

    **Step 2: Initialise a running sum variable**

    - `running_sum`: Set to `0` initially
    - This tracks the sum of all nodes visited so far (all values greater than current)

    &nbsp;

    **Step 3: Perform reverse in-order traversal**

    - Recursively visit the **right subtree** first (larger values)
    - Process the **current node**: add its value to `running_sum`, then update the node's value to `running_sum`
    - Recursively visit the **left subtree** (smaller values)

    &nbsp;

    **Step 4: Return the modified root**

    - The tree is modified in-place during traversal
    - Return the original root reference

  common_pitfalls:
    - title: Using Standard In-Order Traversal
      description: |
        A common mistake is using left → node → right traversal. This visits nodes in ascending order, but we need descending order to know the sum of greater values before processing each node.

        With ascending order, when you visit a node, you don't yet know the sum of all greater values because you haven't visited them yet!
      wrong_approach: "Standard in-order traversal (left → node → right)"
      correct_approach: "Reverse in-order traversal (right → node → left)"

    - title: Two-Pass Solution
      description: |
        Some might think they need two passes: first to calculate the total sum, then another to update each node. While this works, it's unnecessarily complex.

        The reverse in-order traversal elegantly solves this in a single pass because we naturally visit larger values first.
      wrong_approach: "First pass to sum all values, second pass to update nodes"
      correct_approach: "Single reverse in-order pass with running sum"

    - title: Forgetting to Update Running Sum Before Node Value
      description: |
        The order of operations matters. You must add the current node's value to the running sum **before** updating the node's value, otherwise you lose the original value.

        ```python
        # Wrong order:
        node.val = running_sum  # Lost original value!
        running_sum += node.val  # Now adding the wrong value

        # Correct order:
        running_sum += node.val  # Add original value first
        node.val = running_sum   # Then update node
        ```
      wrong_approach: "Update node value before adding to running sum"
      correct_approach: "Add to running sum first, then update node value"

  key_takeaways:
    - "**Reverse in-order traversal** visits BST nodes in descending order — essential when you need to process from largest to smallest"
    - "**Running accumulator pattern**: maintain a running total during traversal when nodes depend on previously visited values"
    - "**BST property exploitation**: the sorted nature of BSTs enables elegant single-pass solutions"
    - "This problem is identical to LeetCode 1038 (Binary Search Tree to Greater Sum Tree)"

  time_complexity: "O(n). Each node is visited exactly once during the traversal."
  space_complexity: "O(h) where h is the height of the tree. This is the recursion stack space — O(log n) for a balanced tree, O(n) for a skewed tree."

solutions:
  - approach_name: Reverse In-Order Traversal (Recursive)
    is_optimal: true
    code: |
      class TreeNode:
          def __init__(self, val=0, left=None, right=None):
              self.val = val
              self.left = left
              self.right = right

      def convert_bst(root: TreeNode | None) -> TreeNode | None:
          # Running sum of all values greater than current node
          running_sum = 0

          def reverse_inorder(node: TreeNode | None) -> None:
              nonlocal running_sum
              if not node:
                  return

              # Visit right subtree first (larger values)
              reverse_inorder(node.right)

              # Process current node: add to sum, then update node
              running_sum += node.val
              node.val = running_sum

              # Visit left subtree (smaller values)
              reverse_inorder(node.left)

          reverse_inorder(root)
          return root
    explanation: |
      **Time Complexity:** O(n) — Each node visited once.

      **Space Complexity:** O(h) — Recursion stack depth equals tree height.

      The recursive approach directly implements reverse in-order traversal. We use `nonlocal` to maintain the running sum across recursive calls. The tree is modified in-place.

  - approach_name: Reverse In-Order Traversal (Iterative)
    is_optimal: true
    code: |
      def convert_bst(root: TreeNode | None) -> TreeNode | None:
          running_sum = 0
          stack = []
          current = root

          # Iterative reverse in-order: right -> node -> left
          while stack or current:
              # Go as far right as possible
              while current:
                  stack.append(current)
                  current = current.right

              # Process the rightmost unprocessed node
              current = stack.pop()
              running_sum += current.val
              current.val = running_sum

              # Move to left subtree
              current = current.left

          return root
    explanation: |
      **Time Complexity:** O(n) — Each node visited once.

      **Space Complexity:** O(h) — Stack stores at most h nodes.

      The iterative version uses an explicit stack to simulate recursion. We traverse right as far as possible, then process nodes and move left. This avoids recursion overhead and stack overflow for very deep trees.

  - approach_name: Morris Traversal
    is_optimal: true
    code: |
      def convert_bst(root: TreeNode | None) -> TreeNode | None:
          running_sum = 0
          current = root

          while current:
              if not current.right:
                  # No right child: process node, move left
                  running_sum += current.val
                  current.val = running_sum
                  current = current.left
              else:
                  # Find in-order predecessor in right subtree
                  # (leftmost node of right subtree)
                  predecessor = current.right
                  while predecessor.left and predecessor.left != current:
                      predecessor = predecessor.left

                  if not predecessor.left:
                      # Create temporary link back to current
                      predecessor.left = current
                      current = current.right
                  else:
                      # Remove temporary link, process current node
                      predecessor.left = None
                      running_sum += current.val
                      current.val = running_sum
                      current = current.left

          return root
    explanation: |
      **Time Complexity:** O(n) — Each edge traversed at most twice.

      **Space Complexity:** O(1) — No additional space beyond pointers.

      Morris traversal achieves O(1) space by temporarily modifying tree pointers to create "threads" back to ancestors. This is the most space-efficient solution but modifies and restores the tree structure during traversal.
