Given N envelopes, as {W, H} pair, where W as the width and H as the height. One envelope can fit into another if and only if both the width and height of one envelope is smaller than the width and height of the other envelope. Find the maximum number of envelopes that can be put inside another envelope and so on. Rotation of envelope is not allowed.

Examples:
Input: envelope[] = {{4, 3}, {5, 3}, {5, 6}, {1, 2}}
Output: 3
Explanation: The maximum number of envelopes that can be put into another envelope
is 3. ({1, 2}, {4, 3}, {5, 6})Input: envelope[] = {{3, 6}, {5, 4}, {4, 8}, {6, 9}, {10, 7}, {12, 12}}
Output: 4
Explanation:The maximum number of envelopes that can be put into another envelope is 4. ({3, 6}, {4, 8}, {6, 9}, {12, 12})
Table of Content
Naive Approach - O(N²) Time and O(N) Space
The idea is to treat this problem like the Longest Increasing Subsequence (LIS) problem. First, sort envelopes by increasing width. If widths are equal, sort by decreasing height. Then, for each envelope, check how many smaller envelopes can fit inside it.
Steps:
- Sort the array in non-decreasing order of width and if width is same, then consider height.
- Initialize a dp[] array, where dp[i] stores the maximum number of envelopes that can be nested with envelope[i] as the largest envelope.
- For each envelope[i], loop through all envelopes before it. If the width and height of a previous envelope are both smaller, update dp[i] = max(dp[i], dp[j] + 1).
- The maximum value in dp[] gives the maximum number of envelopes that can be nested.
//Driver Code Starts
using namespace std;
// Function that returns the maximum
// number of envelopes that can be
// inserted into another envelopes
//Driver Code Ends
int maxenvelopes(vector<vector<int>>& envelopes)
{
// Number of envelopes
int n = envelopes.size();
if (n == 0)
return 0;
// Sort the envelopes in
// non-decreasing order
sort(envelopes.begin(), envelopes.end(),
[](vector<int>& a, vector<int>& b) {
if(a[0] != b[0]) return a[0] < b[0];
return a[1] < b[1];
});
// Initialize dp[] array
vector<int> dp(n, 1);
// To store the result
int max_envelope = 1;
// Loop through the array
for(int i = 1; i < n; ++i)
{
// Find envelopes count for
// each envelope
for(int j = 0; j < i; ++j)
{
if(envelopes[i][0] > envelopes[j][0] &&
envelopes[i][1] > envelopes[j][1])
{
dp[i] = max(dp[i], dp[j] + 1);
}
}
max_envelope = max(max_envelope, dp[i]);
}
return max_envelope;
}
//Driver Code Starts
int main()
{
// Given the envelopes
vector<vector<int>> envelopes = {{4,3},{5,3},{5,6},{1,2}};
// Function call
cout << maxenvelopes(envelopes);
return 0;
}
//Driver Code Ends
//Driver Code Starts
import java.util.Arrays;
// Function that returns the maximum
// number of envelopes that can be
// inserted into another envelopes
class GFG {
//Driver Code Ends
static int maxenvelopes(int[][] envelopes)
{
// Number of envelopes
int n = envelopes.length;
if (n == 0)
return 0;
// Sort the envelopes in
// non-decreasing order
Arrays.sort(envelopes, (a, b) -> {
if (a[0] != b[0])
return a[0] - b[0];
return a[1] - b[1];
});
// Initialize dp[] array
int[] dp = new int[n];
Arrays.fill(dp, 1);
// To store the result
int max_envelope = 1;
// Loop through the array
for (int i = 1; i < n; ++i) {
// Find envelopes count for
// each envelope
for (int j = 0; j < i; ++j) {
if (envelopes[i][0] > envelopes[j][0]
&& envelopes[i][1] > envelopes[j][1]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
max_envelope = Math.max(max_envelope, dp[i]);
}
return max_envelope;
}
//Driver Code Starts
public static void main(String[] args)
{
// Given the envelopes
int[][] envelopes
= { { 4, 3 }, { 5, 3 }, { 5, 6 }, { 1, 2 } };
// Function call
System.out.println(maxenvelopes(envelopes));
}
}
//Driver Code Ends
#Driver Code Starts
# Function that returns the maximum
# number of envelopes that can be
# inserted into another envelopes
#Driver Code Ends
def maxenvelopes(envelopes):
# Number of envelopes
n = len(envelopes)
if n == 0:
return 0
# Sort the envelopes in
# non-decreasing order
envelopes.sort(key=lambda x: (x[0], x[1]))
# Initialize dp[] array
dp = [1] * n
# To store the result
max_envelope = 1
# Loop through the array
for i in range(1, n):
# Find envelopes count for
# each envelope
for j in range(i):
if envelopes[i][0] > envelopes[j][0] and \
envelopes[i][1] > envelopes[j][1]:
dp[i] = max(dp[i], dp[j] + 1)
max_envelope = max(max_envelope, dp[i])
return max_envelope
#Driver Code Starts
if __name__ == "__main__":
# Given the envelopes
envelopes = [[4,3],[5,3],[5,6],[1,2]]
# Function call
print(maxenvelopes(envelopes))
#Driver Code Ends
//Driver Code Starts
using System;
using System.Collections.Generic;
// Function that returns the maximum
// number of envelopes that can be
// inserted into another envelopes
class GFG {
//Driver Code Ends
static int maxenvelopes(int[,] envelopes) {
// Number of envelopes
int n = envelopes.GetLength(0);
if(n == 0) return 0;
// Convert 2D array to list for sorting
List<int[]> envList = new List<int[]>();
for(int i = 0; i < n; i++)
envList.Add(new int[]{envelopes[i,0], envelopes[i,1]});
// Sort the envelopes in non-decreasing order
envList.Sort((a,b) => {
if(a[0] != b[0]) return a[0] - b[0];
return a[1] - b[1];
});
// Initialize dp[] array
int[] dp = new int[n];
for(int i = 0; i < n; i++) dp[i] = 1;
// To store the result
int max_envelope = 1;
// Loop through the array
for(int i = 1; i < n; i++) {
// Find envelopes count for each envelope
for(int j = 0; j < i; j++) {
if(envList[i][0] > envList[j][0] &&
envList[i][1] > envList[j][1]) {
dp[i] = Math.Max(dp[i], dp[j]+1);
}
}
max_envelope = Math.Max(max_envelope, dp[i]);
}
return max_envelope;
}
//Driver Code Starts
static void Main() {
// Given the envelopes
int[,] envelopes = new int[,] { {4,3},{5,3},{5,6},{1,2} };
// Function call
Console.WriteLine(maxenvelopes(envelopes));
}
}
//Driver Code Ends
//Driver Code Starts
// Function that returns the maximum
// number of envelopes that can be
// inserted into another envelopes
//Driver Code Ends
function maxenvelopes(envelopes)
{
// Number of envelopes
let n = envelopes.length;
if (n === 0)
return 0;
// Sort the envelopes in
// non-decreasing order
envelopes.sort((a, b) => {
if (a[0] !== b[0])
return a[0] - b[0];
return a[1] - b[1];
});
// Initialize dp[] array
let dp = new Array(n).fill(1);
// To store the result
let max_envelope = 1;
// Loop through the array
for (let i = 1; i < n; i++) {
// Find envelopes count for
// each envelope
for (let j = 0; j < i; j++) {
if (envelopes[i][0] > envelopes[j][0]
&& envelopes[i][1] > envelopes[j][1]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
max_envelope = Math.max(max_envelope, dp[i]);
}
return max_envelope;
}
//Driver Code Starts
const envelopes =
[ [ 4, 3 ], [ 5, 3 ], [ 5, 6 ], [ 1, 2 ] ];
// Function call
console.log(maxenvelopes(envelopes));
//Driver Code Ends
Output
3
Efficient Approach - O(N log N) Time and O(N) Space
To optimize the naive approach the idea is to use the concept of Binary Search and Longest Increasing Subsequence. First, sort envelopes by increasing width. If widths are equal, sort by decreasing height. Then, the problem reduces to finding the longest increasing sequence of heights
using namespace std;
// Function that returns the maximum
// number of envelopes that can be
// inserted into another envelopes
int maxEnvelopes(vector<vector<int>> &envelopes)
{
// Number of envelopes
int N = envelopes.size();
if (N == 0)
return N;
// Sort the envelopes in increasing
// order of width and decreasing order
// of height is width is same
sort(envelopes.begin(), envelopes.end(),
[](vector<int> &a, vector<int> &b) { return a[0] < b[0] or (a[0] == b[0] and a[1] > b[1]); });
// To store the longest increasing
// sequence of height
vector<int> dp;
// Finding LIS of the heights
// of the envelopes
for (int i = 0; i < N; ++i)
{
auto iter = lower_bound(dp.begin(), dp.end(), envelopes[i][1]);
if (iter == dp.end())
dp.push_back(envelopes[i][1]);
else if (envelopes[i][1] < *iter)
*iter = envelopes[i][1];
}
return dp.size();
}
int main()
{
// Given the envelopes
vector<vector<int>> envelopes = {{4, 3}, {5, 3}, {5, 6}, {1, 2}};
// Function Call
cout << maxEnvelopes(envelopes);
return 0;
}
//Driver Code Starts
import java.util.Arrays;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
class GFG {
// Function that returns the maximum
// number of envelopes that can be
// inserted into another envelopes
//Driver Code Ends
static int maxEnvelopes(int[][] envelopes) {
// Number of envelopes
int N = envelopes.length;
if (N == 0)
return 0;
// Sort the envelopes in increasing
// order of width and decreasing order
// of height if width is same
Arrays.sort(envelopes, new Comparator<int[]>() {
@Override
public int compare(int[] a, int[] b) {
return a[0] == b[0] ? b[1] - a[1] : a[0] - b[0];
}
});
// To store the longest increasing
// sequence of height
ArrayList<Integer> dp = new ArrayList<>();
// Finding LIS of the heights
// of the envelopes
for (int i = 0; i < N; i++) {
int idx = Collections.binarySearch(dp, envelopes[i][1]);
if (idx < 0)
idx = -idx - 1;
if (idx == dp.size())
dp.add(envelopes[i][1]);
else
dp.set(idx, envelopes[i][1]);
}
return dp.size();
}
//Driver Code Starts
public static void main(String[] args) {
// Given the envelopes
int[][] envelopes = { {4, 3}, {5, 3}, {5, 6}, {1, 2} };
// Function Call
System.out.println(maxEnvelopes(envelopes));
}
}
// Output: 3
//Driver Code Ends
#Driver Code Starts
from bisect import bisect_left
# Function that returns the maximum
# number of envelopes that can be
# inserted into another envelope
#Driver Code Ends
def max_envelopes(envelopes):
# Number of envelopes
n = len(envelopes)
if n == 0:
return 0
# Sort envelopes by increasing width
# and decreasing height if widths are same
envelopes.sort(key=lambda x: (x[0], -x[1]))
# To store the longest increasing sequence of heights
dp = []
# Finding LIS of the heights of the envelopes
for _, height in envelopes:
idx = bisect_left(dp, height)
if idx == len(dp):
dp.append(height)
else:
dp[idx] = height
return len(dp)
#Driver Code Starts
if __name__ == "__main__":
# Given the envelopes
envelopes = [[4, 3], [5, 3], [5, 6], [1, 2]]
# Function Call
print(max_envelopes(envelopes))
#Driver Code Ends
//Driver Code Starts
using System;
using System.Collections.Generic;
class GFG {
// Function that returns the maximum
// number of envelopes that can be
// inserted into another envelopes
//Driver Code Ends
static int maxEnvelopes(int[][] envelopes)
{
// Number of envelopes
int n = envelopes.Length;
if (n == 0)
return 0;
// Sort the envelopes in increasing
// order of width and decreasing order
// of height if width is same
Array.Sort(envelopes, (a, b) = > {
if (a[0] != b[0])
return a[0] - b[0];
return b[1] - a[1];
});
// To store the longest increasing sequence of
// height
List<int> dp = new List<int>();
// Finding LIS of the heights of the envelopes
for (int i = 0; i < n; i++) {
int height = envelopes[i][1];
int idx = dp.BinarySearch(height);
if (idx < 0)
idx = ~idx;
if (idx == dp.Count)
dp.Add(height);
else
dp[idx] = height;
}
return dp.Count;
}
//Driver Code Starts
static void Main(string[] args)
{
// Given the envelopes
int[][] envelopes = new int[4][];
envelopes[0] = new int[] { 4, 3 };
envelopes[1] = new int[] { 5, 3 };
envelopes[2] = new int[] { 5, 6 };
envelopes[3] = new int[] { 1, 2 };
// Function Call
Console.WriteLine(maxEnvelopes(envelopes));
}
}
//Driver Code Ends
//Driver Code Starts
// Function that returns the maximum
// number of envelopes that can be
// inserted into another envelopes
//Driver Code Ends
function maxEnvelopes(envelopes) {
// Number of envelopes
let N = envelopes.length;
if (N === 0) return N;
// Sort the envelopes in increasing
// order of width and decreasing order
// of height is width is same
envelopes.sort((a, b) => {
if (a[0] === b[0]) {
return b[1] - a[1];
} else {
return a[0] - b[0];
}
});
// To store the longest increasing
// sequence of height
let dp = [];
// Finding LIS of the heights
// of the envelopes
for (let i = 0; i < N; i++) {
let iter = dp.findIndex(x => x >= envelopes[i][1]);
if (iter === -1) {
dp.push(envelopes[i][1]);
} else if (envelopes[i][1] < dp[iter]) {
dp[iter] = envelopes[i][1];
}
}
return dp.length;
}
//Driver Code Starts
// Driver Code
let envelopes = [[4, 3], [5, 3], [5, 6], [1, 2]];
// Function Call
console.log(maxEnvelopes(envelopes));
// this contributed by devendra
//Driver Code Ends
Output
3