Given height and width of N rectangles. The task is to find the size of the largest subset such that no pair of rectangles fit within each other. Note that if H1 ? H2 and W1 ? W2 then rectangle 1 fits inside rectangle 2.
Examples:
Input: arr[] = {{1, 3}, {2, 2}, {1, 3}}
Output: 2
The required sub-set is {{1, 3}, {2, 2}}
{1, 3} is included only once as it can fit in {1, 3}Input: arr[] = {{1, 5}, {2, 4}, {1, 1}, {3, 3}}
Output: 3
Approach: The above problem can be solved using Dynamic Programming and sorting. Initially, we can sort the N pairs on the basis of heights. A recursive function can be written where there will be two states.
The first state being, if the present rectangle does not fit in the previous rectangle or the vice versa, then we call for the next state with the present rectangle being the previous rectangle and moving to the next rectangle.
dp[present][previous] = max(dp[present][previous], 1 + dp[present + 1][present])
If it does fit in, we call the next state with the previous rectangle and moving to the next rectangle.
dp[present][previous] = max(dp[present][previous], dp[present + 1][previous])
Memoization can be further used to avoid repetitively the same states being called.
Below is the implementation of the above approach:
C++
// C++ implementation of the approach #include <bits/stdc++.h> using namespace std; #define N 10 int dp[N][N]; // Recursive function to get the largest subset int findLongest(pair< int , int > a[], int n, int present, int previous) { // Base case when it exceeds if (present == n) { return 0; } // If the state has been visited previously else if (previous != -1) { if (dp[present][previous] != -1) return dp[present][previous]; } // Initialize int ans = 0; // No elements in subset yet if (previous == -1) { // First state which includes current index ans = 1 + findLongest(a, n, present + 1, present); // Second state which does not include current index ans = max(ans, findLongest(a, n, present + 1, previous)); } else { int h1 = a[previous].first; int h2 = a[present].first; int w1 = a[previous].second; int w2 = a[present].second; // If the rectangle fits in, then do not include // the current index in subset if ((h1 <= h2 && w1 <= w2)) { ans = max(ans, findLongest(a, n, present + 1, previous)); } else { // First state which includes current index ans = 1 + findLongest(a, n, present + 1, present); // Second state which does not include current index ans = max(ans, findLongest(a, n, present + 1, previous)); } } return dp[present][previous] = ans; } // Function to get the largest subset int getLongest(pair< int , int > a[], int n) { // Initialize the DP table with -1 memset (dp, -1, sizeof dp); // Sort the array sort(a, a + n); // Get the answer int ans = findLongest(a, n, 0, -1); return ans; } // Driver code int main() { // (height, width) pairs pair< int , int > a[] = { { 1, 5 }, { 2, 4 }, { 1, 1 }, { 3, 3 } }; int n = sizeof (a) / sizeof (a[0]); cout << getLongest(a, n); return 0; } |
Java
// Java implementation of the above approach. import java.io.*; import java.util.Arrays; import java.util.Comparator; public class GFG { // A function to sort the 2D array by column number. static void Sort( int [][] array, final int columnNumber) { Arrays.sort(array, new Comparator< int []>() { @Override public int compare( int [] first, int [] second) { if (columnNumber >= 1 && first[columnNumber - 1 ] > second[columnNumber - 1 ]) return 1 ; else return - 1 ; } }); } // Recursive function to get the largest subset static int findLongest( int [][] a, int n, int present, int previous, int [][] dp, int N) { // Base case when it exceeds if (present == n) { return 0 ; } // If the state has been visited previously else if (previous != - 1 ) { if (dp[present][previous] != - 1 ) return dp[present][previous]; } // Initialize int ans = 0 ; // No elements in subset yet if (previous == - 1 ) { // First state which includes current index ans = 1 + findLongest(a, n, present + 1 , present, dp, N); // Second state which does not include current // index ans = Math.max(ans, findLongest(a, n, present + 1 , previous, dp, N)); } else { int h1 = a[previous][ 0 ]; int h2 = a[present][ 0 ]; int w1 = a[previous][ 1 ]; int w2 = a[present][ 1 ]; // If the rectangle fits in, then do not include // the current index in subset if ((h1 <= h2 && w1 <= w2)) { ans = Math.max( ans, findLongest(a, n, present + 1 , previous, dp, N)); } else { // First state which includes current index ans = 1 + findLongest(a, n, present + 1 , present, dp, N); // Second state which does not include // current index ans = Math.max( ans, findLongest(a, n, present + 1 , previous, dp, N)); } } if (present >= 0 && previous >= 0 ) { return dp[present][previous] = ans; } return ans; } // Function to get the largest subset static int getLongest( int [][] a, int n) { int N = 10 ; int [][] dp = new int [N + 1 ][N + 1 ]; // Initialize the DP table with -1 for ( int i = 0 ; i < N + 1 ; i++) { for ( int j = 0 ; j < N + 1 ; j++) { dp[i][j] = - 1 ; } } // Sort the array Sort(a, 0 ); // Get the answer int ans = findLongest(a, n, 0 , - 1 , dp, N); return ans; } // Driver code // (height, width) pairs public static void main(String[] args) { int [][] a = { { 1 , 5 }, { 2 , 4 }, { 1 , 1 }, { 3 , 3 } }; int n = a.length; System.out.println(getLongest(a, n)); } } // The code is contributed by Gautam goel (guatamgoel962) |
Python3
# Python3 implementation of the approach # Recursive function to get the # largest subset def findLongest(a, n, present, previous): # Base case when it exceeds if present = = n: return 0 # If the state has been visited # previously elif previous ! = - 1 : if dp[present][previous] ! = - 1 : return dp[present][previous] # Initialize ans = 0 # No elements in subset yet if previous = = - 1 : # First state which includes # current index ans = 1 + findLongest(a, n, present + 1 , present) # Second state which does not # include current index ans = max (ans, findLongest(a, n, present + 1 , previous)) else : h1 = a[previous][ 0 ] h2 = a[present][ 0 ] w1 = a[previous][ 1 ] w2 = a[present][ 1 ] # If the rectangle fits in, then do # not include the current index in subset if h1 < = h2 and w1 < = w2: ans = max (ans, findLongest(a, n, present + 1 , previous)) else : # First state which includes # current index ans = 1 + findLongest(a, n, present + 1 , present) # Second state which does not # include current index ans = max (ans, findLongest(a, n, present + 1 , previous)) dp[present][previous] = ans return ans # Function to get the largest subset def getLongest(a, n): # Sort the array a.sort() # Get the answer ans = findLongest(a, n, 0 , - 1 ) return ans # Driver code if __name__ = = "__main__" : # (height, width) pairs a = [[ 1 , 5 ], [ 2 , 4 ], [ 1 , 1 ], [ 3 , 3 ]] N = 10 # Initialize the DP table with -1 dp = [[ - 1 for i in range (N)] for j in range (N)] n = len (a) print (getLongest(a, n)) # This code is contributed # by Rituraj Jain |
C#
using System; using System.Linq; class GFG { // A function to sort the 2D array by column number. static void Sort( int [][] array, int columnNumber) { Array.Sort(array, (first, second) = > { if (columnNumber >= 1 && first[columnNumber - 1] > second[columnNumber - 1]) { return 1; } else { return -1; } }); } // Recursive function to get the largest subset static int findLongest( int [][] a, int n, int present, int previous, int [][] dp, int N) { // Base case when it exceeds if (present == n) { return 0; } // If the state has been visited previously else if (previous != -1) { if (dp[present][previous] != -1) return dp[present][previous]; } // Initialize int ans = 0; // No elements in subset yet if (previous == -1) { // First state which includes current index ans = 1 + findLongest(a, n, present + 1, present, dp, N); // Second state which does not include current // index ans = Math.Max(ans, findLongest(a, n, present + 1, previous, dp, N)); } else { int h1 = a[previous][0]; int h2 = a[present][0]; int w1 = a[previous][1]; int w2 = a[present][1]; // If the rectangle fits in, then do not include // the current index in subset if ((h1 <= h2 && w1 <= w2)) { ans = Math.Max( ans, findLongest(a, n, present + 1, previous, dp, N)); } else { // First state which includes current index ans = 1 + findLongest(a, n, present + 1, present, dp, N); // Second state which does not include // current index ans = Math.Max( ans, findLongest(a, n, present + 1, previous, dp, N)); } } if (present >= 0 && previous >= 0) { return dp[present][previous] = ans; } return ans; } // Function to get the largest subset static int getLongest( int [][] a, int n) { int N = 10; int [][] dp = new int [N + 1][]; for ( int i = 0; i <= N; i++) dp[i] = Enumerable.Repeat(-1, N + 1).ToArray(); // Sort the array Sort(a, 0); // Get the answer int ans = findLongest(a, n, 0, -1, dp, N); return ans; } // Driver code // (height, width) pairs public static void Main( string [] args) { int [][] a = new int [4][]; a[0] = new int [] { 1, 5 }; a[1] = new int [] { 2, 4 }; a[2] = new int [] { 1, 1 }; a[3] = new int [] { 3, 3 }; int n = a.Length; Console.WriteLine(getLongest(a, n)); } } |
Javascript
<script> // JavaScript implementation of the approach var N = 10; var dp = Array.from(Array(N), ()=>Array(N).fill(-1)); // Recursive function to get the largest subset function findLongest(a, n, present, previous) { // Base case when it exceeds if (present == n) { return 0; } // If the state has been visited previously else if (previous != -1) { if (dp[present][previous] != -1) return dp[present][previous]; } // Initialize var ans = 0; // No elements in subset yet if (previous == -1) { // First state which includes current index ans = 1 + findLongest(a, n, present + 1, present); // Second state which does not include current index ans = Math.max(ans, findLongest(a, n, present + 1, previous)); } else { var h1 = a[previous][0]; var h2 = a[present][0]; var w1 = a[previous][1]; var w2 = a[present][1]; // If the rectangle fits in, then do not include // the current index in subset if ((h1 <= h2 && w1 <= w2)) { ans = Math.max(ans, findLongest(a, n, present + 1, previous)); } else { // First state which includes current index ans = 1 + findLongest(a, n, present + 1, present); // Second state which does not include current index ans = Math.max(ans, findLongest(a, n, present + 1, previous)); } } return dp[present][previous] = ans; } // Function to get the largest subset function getLongest(a, n) { // Initialize the DP table with -1 dp = Array.from(Array(N), ()=>Array(N).fill(-1)); // Sort the array a.sort((a,b)=>a-b); // Get the answer var ans = findLongest(a, n, 0, -1); return ans; } // Driver code // (height, width) pairs var a = [ [ 1, 5 ], [ 2, 4 ], [ 1, 1 ], [ 3, 3 ] ]; var n = a.length; document.write( getLongest(a, n)); </script> |
3
Time Complexity: O(N*N), where dp operations taking N*N time
Auxiliary Space: O(N*N), dp array made of two states each having N space, i.e. N*N
New approach:- Another approach to solve this problem is by using greedy algorithm. We can sort the rectangles in decreasing order of their widths, so that the widest rectangle is considered first. Then, we can add the widest rectangle to the subset and remove all the rectangles that it can contain from the remaining set of rectangles. We can repeat this process with the remaining set of rectangles until we can’t find any more rectangles that fit in the current subset.
Here’s the implementation of the above approach:
C++
#include <iostream> #include <vector> #include <algorithm> using namespace std; int getLongest(vector<pair< int , int >>& arr) { // sort the rectangles in decreasing order of their widths sort(arr.begin(), arr.end(), []( const pair< int , int >& a, const pair< int , int >& b) { return a.second > b.second; }); // initialize the subset with the widest rectangle vector<pair< int , int >> subset = {arr[0]}; // iterate over the remaining rectangles for ( int i = 1; i < arr.size(); i++) { // check if the current rectangle can fit in any rectangle in the subset bool fits = false ; for ( const auto & rect : subset) { if (arr[i].first <= rect.first && arr[i].second <= rect.second) { fits = true ; break ; } } if (!fits) { subset.push_back(arr[i]); } } // return the size of the largest subset return subset.size(); } int main() { vector<pair< int , int >> arr = {{1, 3}, {2, 2}, {1, 3}}; cout << getLongest(arr) << endl; // output: 2 arr = {{1, 5}, {2, 4}, {1, 1}, {3, 3}}; cout << getLongest(arr) << endl; // output: 3 return 0; } |
Java
import java.util.*; public class Main { public static int getLongest( int [][] arr) { // sort the rectangles in decreasing order of their // widths Arrays.sort(arr, new Comparator< int []>() { @Override public int compare( int [] a, int [] b) { return Integer.compare(b[ 1 ], a[ 1 ]); } }); // initialize the subset with the widest rectangle List< int []> subset = new ArrayList<>(); subset.add(arr[ 0 ]); // iterate over the remaining rectangles for ( int i = 1 ; i < arr.length; i++) { int [] rect = arr[i]; // check if the current rectangle can fit in any // rectangle in the subset boolean canFit = false ; for ( int [] r : subset) { if (rect[ 0 ] <= r[ 0 ] && rect[ 1 ] <= r[ 1 ]) { canFit = true ; break ; } } if (!canFit) { subset.add(rect); } } // return the size of the largest subset return subset.size(); } public static void main(String[] args) { int [][] arr1 = { { 1 , 3 }, { 2 , 2 }, { 1 , 3 } }; System.out.println(getLongest(arr1)); // output: 2 int [][] arr2 = { { 1 , 5 }, { 2 , 4 }, { 1 , 1 }, { 3 , 3 } }; System.out.println(getLongest(arr2)); // output: 3 } } |
Python
def getLongest(arr): # sort the rectangles in decreasing order of their widths arr.sort(key = lambda x: x[ 1 ], reverse = True ) # initialize the subset with the widest rectangle subset = [arr[ 0 ]] # iterate over the remaining rectangles for rect in arr[ 1 :]: # check if the current rectangle can fit in any rectangle in the subset if not any (rect[ 0 ] < = r[ 0 ] and rect[ 1 ] < = r[ 1 ] for r in subset): subset.append(rect) # return the size of the largest subset return len (subset) # example usage arr = [( 1 , 3 ), ( 2 , 2 ), ( 1 , 3 )] print (getLongest(arr)) # output: 2 arr = [( 1 , 5 ), ( 2 , 4 ), ( 1 , 1 ), ( 3 , 3 )] print (getLongest(arr)) # output: 3 |
C#
using System; using System.Collections.Generic; using System.Linq; class Program { static int GetLongest(List<Tuple< int , int >> arr) { // sort the rectangles in decreasing order of their widths arr.Sort((a, b) => b.Item2.CompareTo(a.Item2)); // initialize the subset with the widest rectangle List<Tuple< int , int >> subset = new List<Tuple< int , int >> { arr[0] }; // iterate over the remaining rectangles foreach ( var rect in arr.Skip(1)) { // check if the current rectangle can fit in any rectangle in the subset if (!subset.Any(r => rect.Item1 <= r.Item1 && rect.Item2 <= r.Item2)) { subset.Add(rect); } } // return the size of the largest subset return subset.Count; } static void Main( string [] args) { List<Tuple< int , int >> arr = new List<Tuple< int , int >> { Tuple.Create(1, 3), Tuple.Create(2, 2), Tuple.Create(1, 3) }; Console.WriteLine(GetLongest(arr)); // output: 2 arr = new List<Tuple< int , int >> { Tuple.Create(1, 5), Tuple.Create(2, 4), Tuple.Create(1, 1), Tuple.Create(3, 3) }; Console.WriteLine(GetLongest(arr)); // output: 3 } } |
Javascript
function getLongest(arr) { // sort the rectangles in decreasing order of their widths arr.sort((a, b) => b[1] - a[1]); // initialize the subset with the widest rectangle let subset = [arr[0]]; // iterate over the remaining rectangles for (let i = 1; i < arr.length; i++) { const rect = arr[i]; // check if the current rectangle can fit in any rectangle in the subset if (!subset.some(r => rect[0] <= r[0] && rect[1] <= r[1])) { subset.push(rect); } } // return the size of the largest subset return subset.length; } // example usage const arr1 = [ [1, 3], [2, 2], [1, 3] ]; console.log(getLongest(arr1)); // output: 2 const arr2 = [ [1, 5], [2, 4], [1, 1], [3, 3] ]; console.log(getLongest(arr2)); // output: 3 |
2 3
Time Complexity:- The time complexity of the above approach is O(n^2), where n is the number of rectangles. However, since we are sorting the rectangles based on their widths, the actual running time may be lower in practice.
Ready to dive in? Explore our Free Demo Content and join our DSA course, trusted by over 100,000 neveropen!