Russian Doll Envelopes

HardDynamic Programming · LIS · Sort + Binary Search🧩 Longest Increasing SubsequenceLeetCode #354 ↗Updated

Problem

Each envelope is a pair [w, h]. One envelope fits inside another only if both its width and height are strictly smaller; envelopes cannot be rotated. Return the maximum number of envelopes you can nest one inside another.
Input[[5,4],[6,4],[6,7],[2,3]]Output3 ([2,3]→[5,4]→[6,7])
Input[[1,1],[1,1],[1,1]]Output1

1 ≤ n ≤ 105  ·  1 ≤ w, h ≤ 105

Try it yourself

Java
class Solution {
    public int maxEnvelopes(int[][] envelopes) {
        
    }
}
Your code is saved in this browser.Submit on LeetCode ↗
Key insight
Sort by width ascending, and for equal widths by height descending. Then any strictly increasing run of heights automatically has strictly increasing widths, so the answer is just the LIS of the heights.
PatternLongest Increasing Subsequence

Instinct Longest chain where each pick must beat the last (bigger, later, fits inside) - O(n²) best-ending-here DP, or O(n log n) tails plus binary search.

Memory hack Patience solitaire - drop each card on the leftmost pile whose top is not smaller; the number of piles is the LIS length.

Open the Longest Increasing Subsequence guide →

Approaches

Brute ForceSort by Width + Recursion (Take / Skip)

Time O(2n)Space O(n)

After sorting by width, any nesting chain appears left-to-right. Recurse like LIS: at index i skip it, or take it if it is strictly larger in both dimensions than the last taken envelope prev.

Java
public int maxEnvelopes(int[][] envelopes) {
    Arrays.sort(envelopes, (a, b) -> a[0] - b[0]);
    return best(envelopes, 0, -1);
}
private int best(int[][] e, int i, int prev) {
    if (i == e.length) return 0;
    int skip = best(e, i + 1, prev);
    int take = 0;
    if (prev == -1 || (e[i][0] > e[prev][0] && e[i][1] > e[prev][1]))
        take = 1 + best(e, i + 1, i);
    return Math.max(skip, take);
}

Correct and obvious, but explores every subset — exponential.

At a glance

LevelApproachTimeSpace
Brute ForceSort by Width + Recursion (Take / Skip)O(2n)O(n)
BetterSort + O(n2) LIS DPO(n2)O(n)
OptimalSort (w↑, h↓) + Patience LIS on HeightsO(n log n)O(n)
Common pitfalls
  • Sorting equal widths by height ascending — nests same-width envelopes.
  • Using ≤ in either dimension — nesting must be strict.
  • Running the O(n2) DP at n = 105 — times out.
Interview tips
  • Say: “this is 2D LIS — sort one dimension away”.
  • Explain the tie-break before coding; it is the whole trick.
  • Reuse LIS (300) binary search verbatim on the heights.
Pattern
Sort one key + LIS on the other → longest chain where two attributes must both strictly grow.
My notes saved in this browser