You are given an array arr[] of n pairs where each pair consists of two integers (a, b) such that a < b. A pair (c, d) can follow another pair (a, b) if and only if b < c. A chain of pairs is a sequence of pairs where each pair can follow the previous one.
Return the length of the longest chain that can be formed using the given pairs. You may arrange the pairs in any order.
Examples:
Input: arr[][] = [[5, 24], [15, 25], [27, 40], [50, 60]]
Output: 3
Explanation: One of the longest pairs is [5, 24] -> [27, 40] -> [50, 60].Input: arr[][] = [[6, 8], [3, 4]]
Output: 2
Explanation: The longest chain pair is [3, 4] -> [6, 8].
Table of Content
DP - Longest Increasing Subsequence Variant - O(n^2) Time and O(n) Time
The key observation is that after sorting the pairs by their first element, we can treat each pair as an element in an LIS like problem.
Instead of checking whether one value is smaller than another, we check whether the second value of the previous pair is smaller than the first value of the current pair.
If arr[j][1] < arr[i][0], then pair i can follow pair j, so we can extend the chain ending at j.
- Sort all pairs in increasing order of their first element.
- Create a dp[] array where dp[i] = 1, representing the longest chain ending at pair i.
- For each pair i, check all previous pairs j.
- If arr[j][1] < arr[i][0], pair i can follow pair j, so update dp[i] = max(dp[i], dp[j] + 1).
- Return the maximum value in dp[] as the length of the longest chain.
#include <bits/stdc++.h>
using namespace std;
int maxChainLen(vector<vector<int>> &arr)
{
int n = arr.size();
if (n == 0)
return 0;
// Sort pairs by their first element
sort(arr.begin(), arr.end());
// dp[i] = maximum chain length ending at pair i
vector<int> dp(n, 1);
// Try to extend the chain ending at every previous pair
for (int i = 1; i < n; i++)
{
for (int j = 0; j < i; j++)
{
// Pair j can be followed by pair i
// if the second value of j is smaller
// than the first value of i
if (arr[j][1] < arr[i][0])
{
dp[i] = max(dp[i], dp[j] + 1);
}
}
}
// The answer is the maximum chain length
return *max_element(dp.begin(), dp.end());
}
int main()
{
vector<vector<int>> arr = {{5, 24}, {15, 25}, {27, 40}, {50, 60}};
cout << maxChainLen(arr) << endl;
return 0;
}
import java.util.*;
class GFG {
static int maxChainLen(int[][] arr)
{
int n = arr.length;
if (n == 0)
return 0;
// Sort pairs by their first element
Arrays.sort(arr, (a, b) -> {
if (a[0] != b[0])
return Integer.compare(a[0], b[0]);
return Integer.compare(a[1], b[1]);
});
// dp[i] = maximum chain length ending at pair i
int[] dp = new int[n];
Arrays.fill(dp, 1);
// Try to extend the chain ending at every previous
// pair
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
// Pair j can be followed by pair i
// if the second value of j is smaller
// than the first value of i
if (arr[j][1] < arr[i][0]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
// The answer is the maximum chain length
int ans = 0;
for (int i = 0; i < n; i++) {
ans = Math.max(ans, dp[i]);
}
return ans;
}
public static void main(String[] args)
{
int[][] arr = {
{ 5, 24 }, { 15, 25 }, { 27, 40 }, { 50, 60 }
};
System.out.println(maxChainLen(arr));
}
}
def maxChainLen(arr):
n = len(arr)
if n == 0:
return 0
# Sort pairs by their first element
arr.sort()
# dp[i] = maximum chain length ending at pair i
dp = [1] * n
# Try to extend the chain ending at every previous pair
for i in range(1, n):
for j in range(i):
# Pair j can be followed by pair i
# if the second value of j is smaller
# than the first value of i
if arr[j][1] < arr[i][0]:
dp[i] = max(dp[i], dp[j] + 1)
# The answer is the maximum chain length
return max(dp)
# Driver Code
if __name__ == "__main__":
arr = [
[5, 24],
[15, 25],
[27, 40],
[50, 60]
]
print(maxChainLen(arr))
using System;
class GFG {
// Comparator to sort pairs by their first element
class PairComparer
: System.Collections.Generic.IComparer<int[]> {
public int Compare(int[] a, int[] b)
{
if (a[0] != b[0])
return a[0].CompareTo(b[0]);
return a[1].CompareTo(b[1]);
}
}
static int maxChainLen(int[][] arr)
{
int n = arr.Length;
if (n == 0)
return 0;
// Sort pairs by their first element
Array.Sort(arr, new PairComparer());
// dp[i] = maximum chain length ending at pair i
int[] dp = new int[n];
for (int i = 0; i < n; i++)
dp[i] = 1;
// Try to extend the chain ending at every previous
// pair
for (int i = 1; i < n; i++) {
for (int j = 0; j < i; j++) {
// Pair j can be followed by pair i
// if the second value of j is smaller
// than the first value of i
if (arr[j][1] < arr[i][0]) {
dp[i] = Math.Max(dp[i], dp[j] + 1);
}
}
}
// The answer is the maximum chain length
int ans = 0;
for (int i = 0; i < n; i++) {
ans = Math.Max(ans, dp[i]);
}
return ans;
}
static void Main()
{
int[][] arr
= { new int[] { 5, 24 }, new int[] { 15, 25 },
new int[] { 27, 40 },
new int[] { 50, 60 } };
Console.WriteLine(maxChainLen(arr));
}
}
function maxChainLen(arr)
{
const n = arr.length;
if (n === 0)
return 0;
// Sort pairs by their first element
arr.sort((a, b) => {
if (a[0] !== b[0])
return a[0] - b[0];
return a[1] - b[1];
});
// dp[i] = maximum chain length ending at pair i
const dp = new Array(n).fill(1);
// Try to extend the chain ending at every previous pair
for (let i = 1; i < n; i++) {
for (let j = 0; j < i; j++) {
// Pair j can be followed by pair i
// if the second value of j is smaller
// than the first value of i
if (arr[j][1] < arr[i][0]) {
dp[i] = Math.max(dp[i], dp[j] + 1);
}
}
}
// The answer is the maximum chain length
return Math.max(...dp);
}
// Driver Code
const arr = [ [ 5, 24 ], [ 15, 25 ], [ 27, 40 ], [ 50, 60 ] ];
console.log(maxChainLen(arr));
Output
3
Greedy — Activity Selection Variant - O(n * log(n)) Time and O(1) Space
The idea is to solve it as an activity selection problem, consider the first element of a pair as the start time, and the second element of the pair as the end time.
Sort all pairs by their end time and always select the pair that finishes earliest and can follow the previously selected pair.
After selecting a pair, update the end time of the last selected pair. Choosing the pair that finishes earliest leaves more room for the remaining pairs, allowing us to form the maximum possible chain.
- Sort all pairs in increasing order of their second element (ending value).
- Set prev as the ending value of the last selected pair and initialize it to INT_MIN.
- Start checking pairs from the beginning after sorting.
- For each pair (a, b), check whether its starting value a is greater than prev.
If yes, this pair can be added to the chain. - When a pair is selected, increase ans by 1 and set prev = b, because this pair is now the last pair in the chain.
- Continue until all pairs are checked.
#include <bits/stdc++.h>
using namespace std;
int maxChainLen(vector<vector<int>> &arr)
{
int n = arr.size();
if (n == 0)
return 0;
// Comparator to sort pairs by their second element
auto comp = [](vector<int> &a, vector<int> &b) { return a[1] < b[1]; };
// Sort pairs by their second element
sort(arr.begin(), arr.end(), comp);
int prev = INT_MIN;
int ans = 0;
for (int i = 0; i < n; i++)
{
// Select the pair if it can follow the previous pair
if (arr[i][0] > prev)
{
ans++;
// Update the ending value
prev = arr[i][1];
}
}
return ans;
}
int main()
{
vector<vector<int>> arr = {{5, 24}, {15, 25}, {27, 40}, {50, 60}};
cout << maxChainLen(arr) << endl;
return 0;
}
import java.util.*;
class GFG {
static int maxChainLen(int[][] arr)
{
int n = arr.length;
if (n == 0)
return 0;
// Comparator to sort pairs by their second element
Comparator<int[]> comp
= (a, b) -> Integer.compare(a[1], b[1]);
// Sort pairs by their second element
Arrays.sort(arr, comp);
int prev = Integer.MIN_VALUE;
int ans = 0;
for (int i = 0; i < n; i++) {
// Select the pair if it can follow the previous
// pair
if (arr[i][0] > prev) {
ans++;
// Update the ending value
prev = arr[i][1];
}
}
return ans;
}
public static void main(String[] args)
{
int[][] arr = {
{ 5, 24 }, { 15, 25 }, { 27, 40 }, { 50, 60 }
};
System.out.println(maxChainLen(arr));
}
}
def maxChainLen(arr):
n = len(arr)
if n == 0:
return 0
# Comparator to sort pairs by their second element
def comp(pair):
return pair[1]
# Sort pairs by their second element
arr.sort(key=comp)
prev = float('-inf')
ans = 0
for i in range(n):
# Select the pair if it can follow the previous pair
if arr[i][0] > prev:
ans += 1
# Update the ending value
prev = arr[i][1]
return ans
# Driver Code
if __name__ == "__main__":
arr = [
[5, 24],
[15, 25],
[27, 40],
[50, 60]
]
print(maxChainLen(arr))
using System;
class GFG {
static int maxChainLen(int[][] arr)
{
int n = arr.Length;
if (n == 0)
return 0;
// Comparator to sort pairs by their second element
Array.Sort(arr, (a, b) => a[1].CompareTo(b[1]));
// Sort pairs by their second element
int prev = int.MinValue;
int ans = 0;
for (int i = 0; i < n; i++) {
// Select the pair if it can follow the previous
// pair
if (arr[i][0] > prev) {
ans++;
// Update the ending value
prev = arr[i][1];
}
}
return ans;
}
static void Main()
{
int[][] arr
= { new int[] { 5, 24 }, new int[] { 15, 25 },
new int[] { 27, 40 },
new int[] { 50, 60 } };
Console.WriteLine(maxChainLen(arr));
}
}
function maxChainLen(arr)
{
const n = arr.length;
if (n === 0)
return 0;
// Comparator to sort pairs by their second element
const comp = (a, b) => a[1] - b[1];
// Sort pairs by their second element
arr.sort(comp);
let prev = -Infinity;
let ans = 0;
for (let i = 0; i < n; i++) {
// Select the pair if it can follow the previous
// pair
if (arr[i][0] > prev) {
ans++;
// Update the ending value
prev = arr[i][1];
}
}
return ans;
}
// Driver Code
const arr = [ [ 5, 24 ], [ 15, 25 ], [ 27, 40 ], [ 50, 60 ] ];
console.log(maxChainLen(arr));
Output
3