Talentd
FleetCode
Make and follow sheets.Sign in

Russian Doll Envelopes solution and explanation

HardArrayBinary SearchDynamic ProgrammingSorting4 min read37.8% acceptanceUpdated 9 Apr 2026
Russian Doll Envelopes | Dynamic Programming | Leetcode #354 | LISTechdose · 13:15 · 36K viewsWatch on YouTube
9 more videos on this problem
  1. Russian Doll Envelopes | Dynamic Programming | Leetcode #354 | LISTechdose · 13:15 · 36K views
  2. Russian Doll Envelopes | Live Coding with Explanation | Leetcode - 354Algorithms Made Easy · 14:39 · 7K views
  3. #Leetcode 354. Russian Doll Envelopes || Code+ Explanation with examplesCode with Alisha · 19:57 · 5K views
  4. Russian Doll Envelopes | Leetcode 354 | Patience Sort🔥🔥🔥 | O(nlogn) | Live coding sessionCoding Decoded · 7:41 · 5K views
  5. Leetcode - Russian Doll Envelopes (Python)Timothy H Chang · 6:44 · 4K views
  6. Russian Doll Envelopes | LeetCode Hard #354ForAllEpsilon · 9:43 · 1K views
  7. Daily Leetcode #785: May 25, 2022 - 354. Russian Doll EnvelopesProgramming Live with Larry · 18:50 · 1K views
  8. LeetCode 354. Russian Doll EnvelopesHappy Coding · 37:10 · 1K views
  9. Russian Doll Envelopes | Leetcode 354 LC (Hard) | Live coding session | March 30/31Coding Decoded · 13:56 · 1K views
  10. RUSSIAN DOLL ENVELOPES | DP | O(N^2) & O(NLOGN) | 354 LEETCODE | LEETCODE EXPLORE | DAY 30CodeWithSunny · 23:01 · 1K views

The problem

You are given a 2D array of integers envelopes where envelopes[i] = [wi, hi] represents the width and the height of an envelope.

One envelope can fit into another if and only if both the width and height of one envelope are greater than the other envelope's width and height.

Return the maximum number of envelopes you can Russian doll (i.e., put one inside the other).

Note: You cannot rotate an envelope.

Example 1:

Input: envelopes = [[5,4],[6,4],[6,7],[2,3]]
Output: 3
Explanation: The maximum number of envelopes you can Russian doll is 3 ([2,3] => [5,4] => [6,7]).

Example 2:

Input: envelopes = [[1,1],[1,1],[1,1]]
Output: 1

Constraints:

  • 1 <= envelopes.length <= 105
  • envelopes[i].length == 2
  • 1 <= wi, hi <= 105

Approach overview

Problem Overview: You are given envelopes with width and height. One envelope can fit inside another only if both width and height are strictly larger. The task is to compute the maximum number of envelopes you can nest inside each other, similar to Russian dolls.

Approach 1: Dynamic Programming (O(n²) time, O(n) space)

Start by sorting envelopes by width in ascending order. If widths are equal, sort by height to keep ordering consistent. After sorting, the problem becomes similar to finding the longest increasing subsequence (LIS) based on envelope height while ensuring widths increase. Use a DP array where dp[i] stores the maximum number of envelopes ending with envelope i. Iterate through previous envelopes and update dp[i] when both width and height are increasing. This approach clearly demonstrates the relationship to dynamic programming, but the nested loop results in O(n²) time.

Approach 2: Binary Search Optimization (O(n log n) time, O(n) space)

The optimal solution converts the problem into a longest increasing subsequence on heights. First sort envelopes by width ascending, but when widths are equal sort heights in descending order. This trick prevents envelopes with the same width from being counted in the subsequence. After sorting, extract heights and compute LIS using a binary search technique. Maintain a list where each element represents the smallest possible tail for an increasing subsequence of a given length. For every height, use binary search to find the replacement position. This reduces the LIS computation to O(n log n). The method combines sorting, array traversal, and binary search to achieve optimal performance.

Recommended for interviews: The binary search LIS approach is the expected solution in most interviews because it improves the complexity from O(n²) to O(n log n). Still, explaining the DP formulation first shows that you understand the subsequence relationship before optimizing it with binary search.

Approach 1: Dynamic Programming Approach

In this approach, we first sort the envelopes by width and then by height in descending order (if widths are equal). This allows us to look for the longest increasing subsequence of the heights while ignoring the widths. We then use a dynamic programming array to keep track of the maximum sequence length found so far.

def maxEnvelopes(envelopes):
    envelopes.sort(key=lambda x: (x[0], -x[1]))
    dp = []
    for _, h in envelopes:
        i = bisect_left(dp, h)
        if i == len(dp):
            dp.append(h)
        else:
            dp[i] = h
    return len(dp)
import java.util.Arrays;
public class Solution {
    public int maxEnvelopes(int[][] envelopes) {
        Arrays.sort(envelopes, (a, b) -> a[0] == b[0] ? b[1] - a[1] : a[0] - b[0]);
        int[] dp = new int[envelopes.length];
        int len = 0;
        for (int[] envelope : envelopes) {
            int index = Arrays.binarySearch(dp, 0, len, envelope[1]);
            if (index < 0) index = -(index + 1);
            dp[index] = envelope[1];
            if (index == len) len++;
        }
        return len;
    }
}

This Python solution sorts the envelopes, then iterates through them to find the longest increasing subsequence of heights using binary search from the bisect module.

Complexity

Time Complexity: O(n log n), where n is the number of envelopes, due to sorting and binary search operations.

Space Complexity: O(n) for the dp array.

Try this approach in the editor

Approach 2: Binary Search Optimization

This approach involves sorting and using a binary search to optimize the search through the height for the longest increasing subsequence. This enhances efficiency over a simple dynamic programming solution due to reduced overhead from repeated searches.

#include <vector>
#include <algorithm>
using namespace std;
class Solution {
public:
    int maxEnvelopes(vector<vector<int>>& envelopes) {
        sort(envelopes.begin(), envelopes.end(), [](const vector<int>& a, const vector<int>& b) {
            return a[0] == b[0] ? b[1] < a[1] : a[0] < b[0];
        });
        vector<int> dp;
        for (const auto& envelope : envelopes) {
            int height = envelope[1];
            auto it = lower_bound(dp.begin(), dp.end(), height);
            if (it == dp.end()) {
                dp.push_back(height);
            } else {
                *it = height;
            }
        }
        return dp.size();
    }
};
var maxEnvelopes = function(envelopes) {
    envelopes.sort((a, b) => a[0] - b[0] || b[1] - a[1]);
    let dp = [];
    for (let envelope of envelopes) {
        let height = envelope[1];
        let left = 0, right = dp.length;
        while (left < right) {
            let mid = Math.floor((left + right) / 2);
            if (dp[mid] < height) left = mid + 1;
            else right = mid;
        }
        dp[left] = height;
        if (left === dp.length) dp.push(height);
    }
    return dp.length;
};

This C++ solution involves sorting the envelopes and then using lower_bound to perform a binary search on the dp array, which stores the longest increasing subsequence of heights.

Complexity

Time Complexity: O(n log n) because of sorting and binary search operations.

Space Complexity: O(n) to store the dp list.

Try this approach in the editor

Approach 3: Default Approach

func maxEnvelopes(envelopes [][]int) int {
	sort.Slice(envelopes, func(i, j int) bool {
		if envelopes[i][0] != envelopes[j][0] {
			return envelopes[i][0] < envelopes[j][0]
		}
		return envelopes[j][1] < envelopes[i][1]
	})
	n := len(envelopes)
	d := make([]int, n+1)
	d[1] = envelopes[0][1]
	size := 1
	for _, e := range envelopes[1:] {
		x := e[1]
		if x > d[size] {
			size++
			d[size] = x
		} else {
			left, right := 1, size
			for left < right {
				mid := (left + right) >> 1
				if d[mid] >= x {
					right = mid
				} else {
					left = mid + 1
				}
			}
			if d[left] < x {
				left = 1
			}
			d[left] = x
		}
	}
	return size
}
Try this approach in the editor

Complexity comparison

ApproachComplexity
Dynamic Programming Approach

Time Complexity: O(n log n), where n is the number of envelopes, due to sorting and binary search operations.

Space Complexity: O(n) for the dp array.

Binary Search Optimization

Time Complexity: O(n log n) because of sorting and binary search operations.

Space Complexity: O(n) to store the dp list.

Default Approach–

Complexity analysis

ApproachTimeSpaceWhen to Use
Dynamic Programming (LIS style)O(n²)O(n)Good for understanding the LIS relationship and when constraints are small.
Binary Search LIS OptimizationO(n log n)O(n)Preferred for large inputs and the standard optimal interview solution.

Frequently asked questions

Is Russian Doll Envelopes easy or hard?

Russian Doll Envelopes is categorized as a Hard problem because it requires recognizing the transformation to a Longest Increasing Subsequence problem and applying a sorting trick with binary search optimization.

Russian Doll Envelopes Python/Java solution

Implementations usually start by sorting envelopes and then computing the LIS of heights. Python and Java commonly use binary search (bisect in Python or Arrays.binarySearch logic in Java) to maintain the subsequence tails in O(n log n) time.

How to solve Russian Doll Envelopes in O(n log n)?

Sort envelopes by width ascending and height descending when widths are equal. Then run a Longest Increasing Subsequence algorithm on the heights array using binary search to maintain the smallest possible tail values for subsequences.

What is the best approach for Russian Doll Envelopes?

The optimal approach sorts envelopes by width ascending and height descending, then finds the Longest Increasing Subsequence (LIS) of heights using binary search. This reduces the complexity to O(n log n) and avoids counting envelopes with the same width.

Is Russian Doll Envelopes asked at Google/Amazon/Meta?

Russian Doll Envelopes is a classic LIS-based interview problem and has appeared in coding interviews at large tech companies including Google, Amazon, and Meta. It tests sorting strategy and subsequence optimization.

What data structure is used in Russian Doll Envelopes?

The optimal solution primarily uses arrays along with binary search to maintain the tails of increasing subsequences. Sorting and dynamic programming concepts are also involved.

What is the time complexity of Russian Doll Envelopes?

The optimal solution runs in O(n log n) time due to sorting and binary search operations during the LIS computation. A simpler dynamic programming approach exists with O(n²) time complexity and O(n) space.

Comments

Now write it yourselfClose this page and solve Russian Doll Envelopes in the editor, without looking.
Practise Russian Doll Envelopes