[Medium] 354. Russian Doll Envelopes
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.
Examples
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
Explanation: No envelope can fit into another envelope.
Constraints
1 <= envelopes.length <= 10^5envelopes[i].length == 21 <= wi, hi <= 10^5
Thinking Process
- 2D LIS Problem: This is essentially finding LIS in 2D space
- The search space must shrink monotonically each step.
- Decide which half still satisfies the predicate, discard the other.
- Use
mid = left + (right - left) / 2to avoid overflow.
Common Approaches
Typical techniques for this pattern:
| Approach | Time | Space | Notes |
|---|---|---|---|
| Standard binary search (this problem) | O(log n) | O(1) | Sorted array, left <= right |
| Lower / upper bound | O(log n) | O(1) | First/last position, insert index |
| Binary search on rotated array | O(log n) | O(1) | Identify sorted half, discard other |
| Binary search on answer | O(n log M) | O(1) | Monotonic predicate over search space |
Solution
class Solution:
def maxEnvelopes(self, envelopes):
if not envelopes:
return 0
envelopes.sort(key=lambda x: (x[0], -x[1]))
N = len(envelopes)
dp = []
for i in range(N):
num = envelopes[i][1]
if not dp or num > dp[-1]:
dp.append(num)
else:
# lower_bound equivalent
left, right = 0, len(dp) - 1
while left < right:
mid = (left + right) // 2
if dp[mid] >= num:
right = mid
else:
left = mid + 1
dp[left] = num
return len(dp)
Solution Explanation
Approach: Standard binary search (this problem)
Key idea: 1. 2D LIS Problem: This is essentially finding LIS in 2D space
How the code works:
- 2D LIS Problem: This is essentially finding LIS in 2D space
- The search space must shrink monotonically each step.
- Decide which half still satisfies the predicate, discard the other.
- Use
mid = left + (right - left) / 2to avoid overflow.
Walkthrough — input envelopes = [[5,4],[6,4],[6,7],[2,3]], expected output 3:
The maximum number of envelopes you can Russian doll is 3 ([2,3] => [5,4] => [6,7]).
Common Mistakes
- Empty input:
envelopes = []→ return0 - Single envelope:
envelopes = [[1,1]]→ return1 - All same size:
envelopes = [[1,1],[1,1],[1,1]]→ return1 - No valid chain: All envelopes have same width → return
1 -
Perfect chain: Envelopes form a perfect chain → return
n - Wrong sorting order: Not sorting heights descending for equal widths
- Using strict inequality: Must use
>not>=for fitting condition - Not handling empty input: Should return
0for empty array - Wrong LIS implementation: Not using binary search optimization
- Forgetting equal width constraint: Multiple envelopes with same width can’t be in chain
Related Problems
- LC 300: Longest Increasing Subsequence - 1D LIS problem
- LC 673: Number of Longest Increasing Subsequence - Count number of LIS
- LC 646: Maximum Length of Pair Chain - Similar interval chaining
- LC 334: Increasing Triplet Subsequence - Check if triplet exists
Key Takeaways
- 2D LIS Problem: This is essentially finding LIS in 2D space
- Sorting Strategy: Sort by one dimension, then find LIS on the other
- Equal Width Handling: Sort heights descending for equal widths to prevent invalid chains
- Binary Search Optimization: Use
lower_boundfor O(log n) insertion - Greedy Approach: Maintain smallest tail elements for each subsequence length
References
- LC 354: Russian Doll Envelopes on LeetCode
- LeetCode Discuss — LC 354: Russian Doll Envelopes
- LeetCode Editorial (may require premium)