Open In App

Largest subset of rectangles such that no rectangle fit in any other rectangle

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

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:
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>


Output: 

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


Output

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.



Last Updated : 10 Apr, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads