Skip to content
dsa450for five year olds

Binary Search Trees · 17 of 22

Replace every element with the least greater element on its right

For each number in a row, find the smallest bigger number somewhere to its right, by reading the row backwards into a sorted tree.

Simple way
time O(n^2)
room O(1)
Clever way
time O(n h)
room O(n)

The problem, simply

You get an array of numbers. Replace each number with the smallest number that is bigger than it and sits somewhere to its right. If no number to its right is bigger, write -1.

Note the difference from "next greater element": we do not want the first bigger number to the right, we want the smallest bigger one anywhere to the right.

A story to remember it

Picture it

tree
52613879last left turn
arrayinput
0123456773918265i

Read the row from the right and put each number into a BST. When 7 goes in, it turns left at 8, its last left turn. So 8 is the smallest number to its right that is bigger than 7.

  • looking now
  • answer
  • path
  • just added

Examples

A mixed row

In
[7, 3, 9, 1, 8, 2, 6, 5]
Out
[8, 5, -1, 2, -1, 5, -1, -1]

For 3, the bigger numbers to its right are 9, 8, 6 and 5. The smallest of them is 5.

The classic

In
[8, 58, 71, 18, 31, 32, 63, 92, 43, 3, 91, 93, 25, 80, 28]
Out
[18, 63, 80, 25, 32, 43, 80, 93, 80, 25, 93, -1, 28, -1, -1]

For 8, the smallest bigger number to its right is 18, even though 58 comes first.

Going down

In
[5, 4, 3, 2, 1]
Out
[-1, -1, -1, -1, -1]

Nothing to the right of any number is bigger.

Going up

In
[1, 2, 3, 4]
Out
[2, 3, 4, -1]

The smallest bigger number is the very next one.

Repeats

In
[2, 2, 3]
Out
[3, 3, -1]

An equal number is not bigger. Both 2s get 3.

Way 1: the simple way

For each number, scan everything to its right and keep the smallest number that is bigger.

  1. For each i, start with best = infinity.
  2. For each j > i, if a[j] > a[i] and a[j] < best, set best = a[j].
  3. Write best, or -1 if it stayed at infinity.
java
class Solution {
    public int[] leastGreater(int[] a) {
        int n = a.length;
        int[] out = new int[n];
        for (int i = 0; i < n; i++) {
            int best = Integer.MAX_VALUE;
            boolean found = false;
            for (int j = i + 1; j < n; j++) {
                if (a[j] > a[i] && a[j] <= best) {
                    best = a[j];
                    found = true;
                }
            }
            out[i] = found ? best : -1;
        }
        return out;
    }
}

How long it takes: about n * n / 2 comparisons, O(n^2). Extra room besides the answer: O(1).

Way 2: the clever way

Read the array from right to left. Keep a BST of the numbers already read, which are exactly the numbers to the right of the current one.

  1. For i from the last index down to 0, insert a[i] into the BST with a normal walk: smaller goes left, otherwise right.
  2. During the walk, every time you go left at a spot, that spot is bigger than a[i]. Remember it as succ. A later left turn is always at a smaller spot, so the last one is the smallest bigger number.
  3. The answer for i is succ, or -1 if you never turned left.

Read from the right, insert, and note the last left turn

01 / 08

tree
5
arrayinput
0123456773918265i
arrayanswer
01234567-1

Start at the right end. 5 is the first number in the tree. Nothing is to its right, so its answer is -1.

least greater
-1
  • looking now
  • seen
  • done
  • answer
  • path
  • just added
java
class Solution {
    private int succ;                                  // the last left turn of this insert

    public int[] leastGreater(int[] a) {
        int[] out = new int[a.length];
        TreeNode root = null;
        for (int i = a.length - 1; i >= 0; i--) {     // read from the right
            succ = -1;
            root = insert(root, a[i]);
            out[i] = succ;
        }
        return out;
    }

    private TreeNode insert(TreeNode node, int x) {
        if (node == null) return new TreeNode(x);
        if (x < node.val) {
            succ = node.val;                           // bigger than x: a candidate
            node.left = insert(node.left, x);
        } else {
            node.right = insert(node.right, x);        // equal or smaller: not bigger
        }
        return node;
    }
}

How long it takes: each insert walks one road, O(h), so O(n h) in total. That is O(n log n) when the tree stays bushy, but a sorted input makes a stick and O(n^2). Extra room: the tree, O(n).

Another way: a balanced tree from the library

Java's TreeSet is a self balancing BST, so its height stays about log n whatever the input. higher(x) gives the smallest number strictly bigger than x. Since repeats do not matter for this question, a set is enough.

java
import java.util.*;

class Solution {
    public int[] leastGreater(int[] a) {
        int[] out = new int[a.length];
        TreeSet<Integer> right = new TreeSet<>();      // numbers to the right of i
        for (int i = a.length - 1; i >= 0; i--) {
            Integer up = right.higher(a[i]);          // smallest number bigger than a[i]
            out[i] = (up == null) ? -1 : up;
            right.add(a[i]);
        }
        return out;
    }
}

This is a guaranteed O(n log n) with O(n) room. In an interview, write this one, and explain that it is the same left turn idea inside a red black tree.

Watch out for

  • Treating equal as bigger. Use strict x < node.val for a left turn, and send equal numbers right.
  • Reading from the left. The tree must hold only numbers to the right of i, so read from the right end.
  • Forgetting to reset succ to -1 before each insert.

What interviewers ask next

  • Count how many numbers to the right are smaller (LeetCode 315). Same backwards insert, but each spot stores the size of its left side, and every right turn adds that size plus one.
  • The largest smaller number to the right. Mirror it: the last right turn wins, or use TreeSet.lower.
  • Why does a plain BST risk O(n^2)? An already sorted input makes every insert walk the full stick. A balanced tree or shuffling avoids it.
  • Can it be done in O(n log n) without a tree? Yes: sort the indices by value, then for each value find the next index to the right in sorted order using a stack, as in "next greater element" on the sorted list of indices.

Remember this

Grown-up words: the kids already inside are a BST of the suffix, the last left turn is the inorder successor of the new value, higher is the ceiling-above query of a balanced BST, and reading backwards is a right to left sweep.