from bisect import bisect_left
class Solution:
def maxEnvelopes(self, envelopes):
# Sort by width asc, and by height desc for equal widths
envelopes.sort(key=lambda x: (x[0], -x[1]))
heights = [h for w, h in envelopes]
dp = []
for h in heights:
idx = bisect_left(dp, h)
if idx == len(dp):
dp.append(h)
else:
dp[idx] = h
return len(dp)
#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] ? a[1] > b[1] : a[0] < b[0];
});
vector<int> dp;
for (auto& env : envelopes) {
int h = env[1];
auto it = lower_bound(dp.begin(), dp.end(), h);
if (it == dp.end())
dp.push_back(h);
else
*it = h;
}
return dp.size();
}
};
import java.util.*;
class Solution {
public int maxEnvelopes(int[][] envelopes) {
Arrays.sort(envelopes, (a, b) -> a[0] == b[0] ? b[1] - a[1] : a[0] - b[0]);
List<Integer> dp = new ArrayList<>();
for (int[] env : envelopes) {
int h = env[1];
int idx = Collections.binarySearch(dp, h);
if (idx < 0) idx = -(idx + 1);
if (idx == dp.size()) dp.add(h);
else dp.set(idx, h);
}
return dp.size();
}
}
var maxEnvelopes = function(envelopes) {
envelopes.sort((a, b) => a[0] === b[0] ? b[1] - a[1] : a[0] - b[0]);
let dp = [];
for (let env of envelopes) {
let h = env[1];
let left = 0, right = dp.length;
while (left < right) {
let mid = (left + right) >> 1;
if (dp[mid] < h) left = mid + 1;
else right = mid;
}
if (left === dp.length) dp.push(h);
else dp[left] = h;
}
return dp.length;
};
Given a list of envelopes, each described by a pair [width, height]
, you must determine the maximum number of envelopes you can nest ("Russian doll style"). An envelope A
can fit into envelope B
if and only if both A
's width and height are strictly less than B
's width and height. You cannot rotate envelopes, and each envelope can be used at most once. Return the largest number of envelopes that can be nested inside each other.
At first glance, this problem looks similar to finding the longest increasing subsequence (LIS), but in two dimensions. A brute-force approach would involve trying all possible envelope orderings, checking which ones can be nested—a solution that quickly becomes infeasible due to the number of combinations.
To optimize, we notice that if we sort the envelopes appropriately, we can reduce the problem to a 1D LIS problem. The main challenge is dealing with both width and height, as envelopes with the same width but different heights cannot be nested.
The key insight is to sort by width (ascending) and, for equal widths, by height (descending). This prevents envelopes with equal widths from being incorrectly nested. Once sorted, we only need to find the LIS of the heights, as the width constraint is already handled by the sorting.
We can solve the problem efficiently by following these steps:
This approach is efficient and leverages classic LIS optimization techniques.
Let's consider the sample input: [[5,4],[6,4],[6,7],[2,3]]
[[2,3],[5,4],[6,7],[6,4]]
[3,4,7,4]
dp=[]
dp=[3]
dp=[3,4]
dp=[3,4,7]
dp=[3,4,7]
dp
is 3, so the answer is 3.
This means the maximum number of envelopes that can be nested is 3.
The Russian Doll Envelopes problem is a clever variation of the Longest Increasing Subsequence, but in two dimensions. By sorting envelopes by width (and height in reverse for ties), we transform the problem into a classic LIS challenge. Using binary search, we achieve an efficient O(n log n) solution. The key insight is the sorting strategy, which elegantly handles the two-dimensional nesting constraint and simplifies the problem into a manageable form.