DSA sheet · Trees · Binary Search Tree pattern

BST to Greater Tree

In this video the teacher changes every value in a BST to "itself plus everything bigger than it". She calls it an easy question, and it is, once you see the trick. She first builds a brute force from the fact that inorder of a BST is sorted (store the values, take sums from the right end, write them back). Then she asks why we need three passes and an extra array, and gets to the optimal answer: walk the tree in reverse inorder (right, root, left) and keep one running sum. The problem matters because "visit the nodes in sorted order, or in reverse sorted order" is a tool you will reuse in many BST questions.

Every part below follows the same order:
① the question in simple words → ② what the constraints tell us → ③ intuition → ④ building the conditions from examples → ⑤ approach steps → ⑥ code → ⑦ code line by line → ⑧ dry run → ⑨ complexity & remember

Part 0 · Before starting

What is a tree node?

Each node holds a value, a link to its left child and a link to its right child. A missing child is None.

given by LeetCode, don't write this in the solution
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

The BST rule

A binary search tree (BST) is a binary tree where, for every node, all values in its left subtree are smaller and all values in its right subtree are bigger. (A subtree is a node plus everything below it.) The rule covers every node below, not only the direct children.

valid BST ✓
        4
       / \
      1   6
       \
        3
NOT a BST ✗
        4
       / \
      1   6
       \
        7

In the second tree, 7 > 1, so it's fine as 1's right child. But it is inside 4's left subtree and 7 > 4, so the tree breaks the rule. LeetCode also promises all values are different.

Why inorder of a BST is sorted

Inorder = visit the left subtree, then the node, then the right subtree. At every node, the left part holds only smaller values and the right part only bigger ones, so the node is printed exactly between them. Since this is true at every level, the full output comes out in increasing order.

Flip it to right, node, left (the teacher calls it reverse inorder) and you get the same values in decreasing order. That is the key tool for Part B.

Suffix sum (the teacher says "prefix sum from the right")

For an array, the sum "from position i to the end" is called the suffix sum. You build it by walking from the last element to the first and adding as you go. Example: [1, 2, 3] → from the right: 3, 3+2 = 5, 5+1 = 6 → [6, 5, 3].

Part A · Brute force: inorder array + sums from the right

LeetCode 538 (same as LeetCode 1038)

1The question in simple words

You get the root of a BST. Replace every node's value with: its own value + the sum of all values in the tree that are bigger than it. Return the root. The shape of the tree does not change, only the numbers.

input
            4
         /     \
        1       6
       / \     / \
      0   2   5   7
           \       \
            3       8
output (the greater tree)
            30
         /      \
       36        21
      /  \      /  \
    36    35  26    15
            \         \
             33        8

The teacher's two quick checks:

2What the constraints tell us

Doubt: does overflow matter in Python?
→ No, Python integers grow as needed. But this "max possible sum" check is what interviewers want to hear, and it matters if you later write the same code in Java or C++.

3Intuition

The phrase "all values bigger than me" sounds like we need the values in order. A BST gives us sorted order for free through inorder. So: write the values down in sorted order, and the "bigger than me" values are simply everything to my right in that list.

4Building the idea from the example

Inorder of the input tree:

index012345678
inorder value012345678
wanted new value36363533302621158

The teacher fills the wanted row from the right end: 8 → 8; 7 → 7 + 8 = 15; 6 → 6 + 15 = 21; 5 → 5 + 21 = 26; 4 → 30; 3 → 33; 2 → 35; 1 → 36; 0 → 36.

Look at what's happening: each answer is its own value plus the answer just to its right. That's exactly the suffix sum. The answer is hidden in the sorted list itself.

Now we need to put these numbers back into the tree. If we do inorder again, we meet the nodes in the same order (0, 1, 2, …). So the i-th node we meet gets arr[i]:

Walk it: go left from 4 → 1 → 0 → left of 0 is None, come back. First node met is 0 → set it to arr[0] = 36, i = 1. Back to 1 → arr[1] = 36, i = 2. Then 1's right: 2 (its left is None) → arr[2] = 35. Then 3 → 33. And so on.

Doubt: why must the index i live outside the recursive function (in self)?
→ Every recursive call has to see and move the same counter. If each call had its own copy, the increments would be lost when calls return, and several nodes would read the same arr[i].

5Approach steps

  1. Inorder traversal → store all values in arr (sorted).
  2. Walk arr from the last index to the first, keeping a running total; set arr[i] = total.
  3. Set self.i = 0. Inorder traversal again; at each node, set node.val = arr[self.i] and move self.i forward.
  4. Return root.

6Code (Python)

BST to Greater Tree, brute force (3 passes)
class Solution:
    def convertBST(self, root):
        arr = []
        self.inorder(root, arr)                  # pass 1: sorted values

        total = 0
        for i in range(len(arr) - 1, -1, -1):    # pass 2: sums from the right
            total += arr[i]
            arr[i] = total

        self.i = 0
        self.update(root, arr)                   # pass 3: write back
        return root

    def inorder(self, node, arr):
        if node is None:
            return
        self.inorder(node.left, arr)
        arr.append(node.val)
        self.inorder(node.right, arr)

    def update(self, node, arr):
        if node is None:
            return
        self.update(node.left, arr)
        node.val = arr[self.i]                   # instead of saving, overwrite
        self.i += 1
        self.update(node.right, arr)

7Code line by line

linewhat it means
self.inorder(root, arr)Normal inorder. Because it's a BST, arr ends up sorted (smallest first).
for i in range(len(arr) - 1, -1, -1):Go from the last index (biggest value) down to index 0.
total += arr[i] arr[i] = totaltotal is now "this value + all values to its right", i.e. this value plus everything bigger. Store it in place.
self.i = 0The shared counter for the write-back pass.
self.update(node.left, arr)Same order as the first inorder: left first…
node.val = arr[self.i] self.i += 1…then this node. The k-th node visited is the k-th smallest, and it gets the k-th sum.
self.update(node.right, arr)…then the right side.
return rootSame tree, new numbers. For an empty tree, arr stays empty and we return None.

8Dry run (hand table)

stepwhat happensarr after the step
pass 1inorder: 0, 1, 2, 3, 4, 5, 6, 7, 8[0,1,2,3,4,5,6,7,8]
pass 2, i = 8total = 8[…, 7, 8]
i = 7total = 15[…, 6, 15, 8]
i = 6 … 0total = 21, 26, 30, 33, 35, 36, 36[36,36,35,33,30,26,21,15,8]
pass 3inorder again: 0←36, 1←36, 2←35, 3←33, 4←30, 5←26, 6←21, 7←15, 8←8tree now matches the output ✓

9Complexity & remember

It's already linear, so why improve? The teacher asks: why pass over the data three times and keep an extra array at all? Can we do it in one pass with no array?

Remember the brute forceInorder → sorted array → suffix sums → inorder again and write arr[i] into the i-th node.

Part B · Optimal: reverse inorder with a running sum

The question and constraints (steps ① and ②) are the same as in Part A. What changes is the idea.

3Intuition: visit the big values first

In Part A, the suffix sums were built by walking the sorted list from the biggest value down. What if we walk the tree itself in that order? Then, when we reach any node, we have already seen every bigger value, and their total is in our hands.

Normal inorder goes left, node, right (small to big). Swap the sides: right, node, left visits the nodes from big to small. Keep one variable total. At each node: add its value to total, then write total into the node.

4Building the idea: why right first?

The bigger values sit on the right, so that's where we must go first.

Doubt: what if the question asked for "itself + sum of all smaller values"?
→ Then you need the smaller values first, so you'd use normal inorder (left, node, right) and start from 0. The teacher's rule of thumb: start at the node whose answer needs nothing else, and walk in the order that hands each node what it needs.
Doubt: do we still need the extra array?
→ No. In Part A we only ever needed "the sum so far from the right". One number holds that. The array was just storage we didn't need.

5Approach steps

  1. Set self.total = 0.
  2. Reverse inorder from the root: if the node is None, return.
  3. Go to the right subtree first.
  4. Add the node's value to total; set the node's value to total.
  5. Go to the left subtree.
  6. Return root.

6Code (Python)

BST to Greater Tree, optimal (1 pass, no array)
class Solution:
    def convertBST(self, root):
        self.total = 0                           # running sum of bigger values
        self.reverseInorder(root)
        return root

    def reverseInorder(self, node):
        if node is None:
            return
        self.reverseInorder(node.right)          # bigger values first
        self.total += node.val                   # add myself
        node.val = self.total                    # me + everything bigger
        self.reverseInorder(node.left)           # then the smaller ones

7Code line by line

linewhat it means
self.total = 0Before visiting anything, the sum of "bigger values seen" is 0. It lives on self so that every call shares it.
if node is None: returnBase case, same as any inorder. Also handles an empty tree.
self.reverseInorder(node.right)Finish every bigger value first. When this returns, total contains the sum of all values bigger than this node.
self.total += node.valAdd this node's own (original) value.
node.val = self.totalWrite "me + all bigger" into the node. Its old value is no longer needed: it's already inside total.
self.reverseInorder(node.left)Now the smaller values. Each of them will see a total that already includes this node.
Doubt: why is the order of total += node.val and node.val = total important?
→ If you overwrite first, you lose the node's original value and add the wrong thing. Add first, then write.

8Dry run using the call stack

  1. rev(4) → go right → rev(6) → go right → rev(7) → go right → rev(8) → right is None, returns.
  2. At 8: total = 0 + 8 = 8, node 8 → 8. Left is None. rev(8) leaves the stack.
  3. At 7: total = 8 + 7 = 15, node → 15. Left None. Done.
  4. At 6: total = 15 + 6 = 21. Go left → rev(5): right None; total = 21 + 5 = 26; left None.
  5. At 4 (root): total = 26 + 4 = 30. Go left → rev(1) → right → rev(2) → right → rev(3).
  6. At 3: total = 33. At 2: total = 35 (2's left is None).
  7. At 1: total = 36. Go left → rev(0): total = 36 + 0 = 36.
  8. Stack empties. Return the root, which now holds 30. Tree matches the output ✓
stack at step 2
rev(4)rev(6)rev(7)rev(8): total 8
stack at step 4
rev(4)rev(6)rev(5): total 26
stack at step 6
rev(4)rev(1)rev(2)rev(3): total 33
visit order876543210
total after81521263033353636

The visit order is the sorted list read backwards, which is why the teacher names it reverse inorder.

9Complexity & remember

Remember Greater TreeRight → node → left, one running total. At each node: total += val, then val = total.

Part C · Revision page

Brute forceOptimal
ideainorder → array → suffix sums → write backreverse inorder with a running sum
traversal orderleft, node, right (twice)right, node, left (once)
passes31
extra memoryarray of n + stackone number + stack
time / spaceO(n) / O(n)O(n) / O(h)
question asks forvisit orderstart at
itself + all bigger valuesright, node, leftthe largest node
itself + all smaller valuesleft, node, rightthe smallest node
If you remember only 5 lines 1. Inorder of a BST is sorted; reverse inorder is sorted backwards.
2. "Me + all bigger" = suffix sum of the sorted list.
3. Brute force: build the array, take sums from the right, inorder again to write back.
4. Optimal: right, node, left with one shared running total.
5. Add first (total += val), then overwrite (val = total).
Mistakes to avoid ✗ using normal inorder (left first) in the optimal version
✗ keeping total or the index as a local variable inside the recursion
✗ overwriting node.val before adding it to the total
✗ forgetting the None base case (the tree can be empty)
test it yourself (paste under either solution above)
def inorder(n):
    return inorder(n.left) + [n.val] + inorder(n.right) if n else []

root = TreeNode(4,
        TreeNode(1, TreeNode(0), TreeNode(2, None, TreeNode(3))),
        TreeNode(6, TreeNode(5), TreeNode(7, None, TreeNode(8))))
s = Solution()
root = s.convertBST(root)
print(inorder(root))              # [36, 36, 35, 33, 30, 26, 21, 15, 8]
print(root.val)                   # 30
print(s.convertBST(None))         # None
print(s.convertBST(TreeNode(5)).val)   # 5

Based on this video: Convert BST to Greater Tree