Maximum Binary Tree

MediumDivide & Conquer · Monotonic Stack🧩 Recursion & Divide and ConquerLeetCode #654 ↗Updated

Problem

You get an array nums of distinct integers. Build a tree recursively: the largest value becomes the root, the elements to its left in the array form the left subtree (built the same way), and the elements to its right form the right subtree. Return the root.
Input[4,7,1,5,2]Output[7,4,5,null,null,1,2]
Input[1,2,3]Output[3,2,null,1]
Input[9]Output[9]

1 ≤ n ≤ 1000  ·  0 ≤ nums[i] ≤ 1000  ·  all values distinct

Try it yourself

Java
class Solution {
    public TreeNode constructMaximumBinaryTree(int[] nums) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
A node's parent is the smaller of its nearest greater element on the left and on the right. A decreasing stack finds both in one sweep: the nodes a new value pops become its left child, and it becomes the right child of whatever remains on top.
PatternRecursion & Divide and Conquer

Instinct If the answer for n items can be built from the same problem on halves (or smaller pieces) plus a cheap combine step - split, recurse, merge.

Memory hack Split it, trust it, stitch it - nail the base case, take the leap of faith on smaller calls, then glue their answers together.

Open the Recursion & Divide and Conquer guide →

Approaches

Brute ForceDirect Recursion with Linear Max Scan

Time O(n²)Space O(n)

Follow the definition literally: scan [lo, hi] for the max, make it the root, recurse on both sides. Each level of recursion scans its whole range, so a sorted array (a chain-shaped tree) costs n + (n-1) + … scans.

Java
public TreeNode constructMaximumBinaryTree(int[] nums) {
    return build(nums, 0, nums.length - 1);
}
private TreeNode build(int[] nums, int lo, int hi) {
    if (lo > hi) return null;
    int maxIdx = lo;
    for (int i = lo + 1; i <= hi; i++) {
        if (nums[i] > nums[maxIdx]) maxIdx = i;
    }
    TreeNode root = new TreeNode(nums[maxIdx]);
    root.left = build(nums, lo, maxIdx - 1);
    root.right = build(nums, maxIdx + 1, hi);
    return root;
}

Mirrors the statement; quadratic on sorted input, O(n log n) on random input.

At a glance

LevelApproachTimeSpace
Brute ForceDirect Recursion with Linear Max ScanO(n²)O(n)
BetterRecursion + Sparse Table Range-MaxO(n log n)O(n log n)
OptimalMonotonic Decreasing StackO(n)O(n)
Common pitfalls
  • Returning stack.peek() (the top) — the root is at the bottom.
  • Attaching every popped node as the left child — only the last popped one is.
  • Assuming the recursion is always O(n log n) — sorted input makes it O(n²).
Interview tips
  • Code the recursive definition first; it's short and clearly correct.
  • Point out the worst case (sorted input) to motivate a faster range-max or the stack.
  • Explain the stack via “parent = smaller of the two nearest greater neighbours”.
Pattern
Monotonic stack / Cartesian tree → build or query structure defined by nearest greater (or smaller) elements.
My notes saved in this browser