Maximum Number of Bridges

Last Updated : 10 Jul, 2026

Given two integer arrays arr1[] and arr2[] of same size, where a bridge can be built between point arr1[i] on one bank of a river and point arr2[i] on the opposite bank.

Find the maximum number of bridges that can be constructed such that no two bridges cross each other.

Bridges sharing an endpoint are allowed and are not considered crossing.

It is guaranteed that there is no pair of distinct indices i and j such that both arr1[i] == arr1[j] and arr2[i] == arr2[j]; that is, no two bridges connect the same pair of endpoints.

Examples:

Input: arr1[] = [3, 1, 4, 4], arr2[] = [1, 3, 2, 1]
Output: 3
Explanation: One valid set of non-crossing bridges is (3,1), (4,1), and (4,2). It is not possible to construct more than 3 bridges without creating a crossing.

Input: arr1[] = [1, 1], arr2[] = [1, 2]
Output: 2
Explanation: The two bridges share an endpoint but do not cross each other. Hence, both bridges can be constructed.

[Naive Approach] Generate All Possible Bridge Subsets - O(2 ^ n * n ^ 2) Time and O(n) Space

The idea is to generate every possible subset of bridges and check whether any two selected bridges cross each other. Among all valid subsets, return the maximum number of bridges.

C++
#include <iostream>
#include <vector>
using namespace std;

// Function to check whether selected
// bridges are non-crossing
bool isValid(vector<pair<int, int>> &bridges)
{
    int m = bridges.size();

    // Compare every pair of bridges
    for (int i = 0; i < m; i++)
    {
        for (int j = i + 1; j < m; j++)
        {

            // Check if two bridges cross
            if ((bridges[i].first < bridges[j].first && bridges[i].second > bridges[j].second) ||
                (bridges[i].first > bridges[j].first && bridges[i].second < bridges[j].second))
                return false;
        }
    }

    return true;
}

int maxBridges(vector<int> &arr1, vector<int> &arr2)
{
    int n = arr1.size();
    int ans = 0;

    // Generate every subset
    for (int mask = 0; mask < (1 << n); mask++)
    {
        vector<pair<int, int>> bridges;

        for (int i = 0; i < n; i++)
        {
            if (mask & (1 << i))
                bridges.push_back({arr1[i], arr2[i]});
        }

        if (isValid(bridges))
            ans = max(ans, (int)bridges.size());
    }

    return ans;
}

int main()
{
    vector<int> arr1 = {3, 1, 4, 4};
    vector<int> arr2 = {1, 3, 2, 1};

    cout << maxBridges(arr1, arr2);

    return 0;
}
Java
import java.util.ArrayList;

class GFG {

    // Function to check whether selected bridges are
    // non-crossing
    static boolean isValid(ArrayList<int[]> bridges)
    {
        int m = bridges.size();

        // Compare every pair of bridges
        for (int i = 0; i < m; i++) {
            for (int j = i + 1; j < m; j++) {

                // Check if two bridges cross
                if ((bridges.get(i)[0] < bridges.get(j)[0]
                     && bridges.get(i)[1]
                            > bridges.get(j)[1])
                    || (bridges.get(i)[0]
                            > bridges.get(j)[0]
                        && bridges.get(i)[1]
                               < bridges.get(j)[1]))
                    return false;
            }
        }

        return true;
    }

    public int maxBridges(int[] arr1, int[] arr2)
    {
        int n = arr1.length;
        int ans = 0;

        // Generate every subset
        for (int mask = 0; mask < (1 << n); mask++) {
            ArrayList<int[]> bridges = new ArrayList<>();

            for (int i = 0; i < n; i++) {
                if ((mask & (1 << i)) != 0)
                    bridges.add(
                        new int[] { arr1[i], arr2[i] });
            }

            if (isValid(bridges))
                ans = Math.max(ans, bridges.size());
        }

        return ans;
    }

    public static void main(String[] args)
    {
        int[] arr1 = { 3, 1, 4, 4 };
        int[] arr2 = { 1, 3, 2, 1 };

        GFG obj = new GFG();

        System.out.println(obj.maxBridges(arr1, arr2));
    }
}
Python
# Function to check whether selected
# bridges are non-crossing
def isValid(bridges):
    m = len(bridges)

    # Compare every pair of bridges
    for i in range(m):
        for j in range(i + 1, m):

            # Check if two bridges cross
            if ((bridges[i][0] < bridges[j][0] and bridges[i][1] > bridges[j][1]) or
                    (bridges[i][0] > bridges[j][0] and bridges[i][1] < bridges[j][1])):
                return False

    return True


def maxBridges(arr1, arr2):
    n = len(arr1)
    ans = 0

    # Generate every subset
    for mask in range(1 << n):
        bridges = []

        for i in range(n):
            if mask & (1 << i):
                bridges.append((arr1[i], arr2[i]))

        if isValid(bridges):
            ans = max(ans, len(bridges))

    return ans

if __name__ == "__main__":
    arr1 = [3, 1, 4, 4]
    arr2 = [1, 3, 2, 1]

    print(maxBridges(arr1, arr2))
C#
using System;
using System.Collections.Generic;

class GFG {
    // Function to check whether selected bridges are
    // non-crossing
    static bool IsValid(List<(int, int)> bridges)
    {
        int m = bridges.Count;

        // Compare every pair of bridges
        for (int i = 0; i < m; i++) {
            for (int j = i + 1; j < m; j++) {
                // Check if two bridges cross
                if ((bridges[i].Item1 < bridges[j].Item1
                     && bridges[i].Item2 > bridges[j].Item2)
                    || (bridges[i].Item1 > bridges[j].Item1
                        && bridges[i].Item2
                               < bridges[j].Item2))
                    return false;
            }
        }

        return true;
    }

    public int maxBridges(int[] arr1, int[] arr2)
    {
        int n = arr1.Length;
        int ans = 0;

        // Generate every subset
        for (int mask = 0; mask < (1 << n); mask++) {
            List<(int, int)> bridges
                = new List<(int, int)>();

            for (int i = 0; i < n; i++) {
                if ((mask & (1 << i)) != 0)
                    bridges.Add((arr1[i], arr2[i]));
            }

            if (IsValid(bridges))
                ans = Math.Max(ans, bridges.Count);
        }

        return ans;
    }

    static void Main()
    {
        int[] arr1 = { 3, 1, 4, 4 };
        int[] arr2 = { 1, 3, 2, 1 };

        GFG obj = new GFG();

        Console.WriteLine(obj.maxBridges(arr1, arr2));
    }
}
JavaScript
// Function to check whether selected bridges are
// non-crossing
function isValid(bridges)
{
    let m = bridges.length;

    // Compare every pair of bridges
    for (let i = 0; i < m; i++) {
        for (let j = i + 1; j < m; j++) {

            // Check if two bridges cross
            if ((bridges[i][0] < bridges[j][0]
                 && bridges[i][1] > bridges[j][1])
                || (bridges[i][0] > bridges[j][0]
                    && bridges[i][1] < bridges[j][1]))
                return false;
        }
    }

    return true;
}

function maxBridges(arr1, arr2)
{
    let n = arr1.length;
    let ans = 0;

    // Generate every subset
    for (let mask = 0; mask < (1 << n); mask++) {
        let bridges = [];

        for (let i = 0; i < n; i++) {
            if (mask & (1 << i))
                bridges.push([ arr1[i], arr2[i] ]);
        }

        if (isValid(bridges))
            ans = Math.max(ans, bridges.length);
    }

    return ans;
}

// Driver code
let arr1 = [ 3, 1, 4, 4 ];
let arr2 = [ 1, 3, 2, 1 ];

console.log(maxBridges(arr1, arr2));

Output
3

[Better Approach] Using Sorting with Dynamic Programming (LNDS) - O(n ^ 2) Time and O(n) Space

The idea is to first sort all the bridges by their first endpoints, and by their second endpoints in case of a tie. After sorting, use dynamic programming to find the Longest Non-Decreasing Subsequence (LNDS) of the second bank endpoints, where dp[i] stores the maximum number of non-crossing bridges ending at the i-th bridge. The maximum value in dp gives the maximum number of non-crossing bridges.

Let us understand with an example:
Input: arr1[] = [3, 1, 4, 4], arr2[] = [1, 3, 2, 1]

  • Form the bridge pairs: (3,1), (1,3), (4,2), (4,1) and sort them to get (1,3), (3,1), (4,1), (4,2).
  • Initialize dp = [1, 1, 1, 1] since each bridge alone can form a valid set.
  • For bridge (3,1), no previous bridge has a second endpoint <= 1, so dp = [1, 1, 1, 1].
  • For bridge (4,1), bridge (3,1) satisfies 1 <= 1, so update dp = [1, 1, 2, 1].
  • For bridge (4,2), bridge (3,1) and (4,1) satisfy the condition, giving dp = [1, 1, 2, 3]. The maximum value in dp is 3, so the answer is 3.
C++
#include <iostream>
#include <vector>
using namespace std;

int maxBridges(vector<int> &arr1, vector<int> &arr2)
{
    int n = arr1.size();

    vector<pair<int, int>> bridges;

    // Store all bridges
    for (int i = 0; i < n; i++)
    {
        bridges.push_back({arr1[i], arr2[i]});
    }

    // Sort bridges by first bank and then by second bank
    sort(bridges.begin(), bridges.end());

    vector<int> dp(n, 1);
    int res = 1;

    // Find Longest Non-Decreasing Subsequence
    for (int i = 1; i < n; i++)
    {
        for (int j = 0; j < i; j++)
        {
            if (bridges[j].second <= bridges[i].second)
            {
                dp[i] = max(dp[i], dp[j] + 1);
            }
        }

        res = max(res, dp[i]);
    }

    return res;
}

int main()
{
    vector<int> arr1 = {3, 1, 4, 4};
    vector<int> arr2 = {1, 3, 2, 1};

    cout << maxBridges(arr1, arr2);

    return 0;
}
Java
import java.util.Arrays;

class GFG {

    static int maxBridges(int[] arr1, int[] arr2)
    {
        int n = arr1.length;

        int[][] bridges = new int[n][2];

        // Store all bridges
        for (int i = 0; i < n; i++) {
            bridges[i][0] = arr1[i];
            bridges[i][1] = arr2[i];
        }

        // Sort bridges by first bank and then by second
        // bank
        Arrays.sort(bridges, (a, b) -> {
            if (a[0] != b[0]) {
                return Integer.compare(a[0], b[0]);
            }
            return Integer.compare(a[1], b[1]);
        });

        int[] dp = new int[n];
        Arrays.fill(dp, 1);
        int res = 1;

        // Find Longest Non-Decreasing Subsequence
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < i; j++) {
                if (bridges[j][1] <= bridges[i][1]) {
                    dp[i] = Math.max(dp[i], dp[j] + 1);
                }
            }

            res = Math.max(res, dp[i]);
        }

        return res;
    }

    public static void main(String[] args)
    {
        int[] arr1 = { 3, 1, 4, 4 };
        int[] arr2 = { 1, 3, 2, 1 };
        System.out.println(maxBridges(arr1, arr2));
    }
}
Python
def maxBridges(arr1, arr2):
    n = len(arr1)

    bridges = []

    # Store all bridges
    for i in range(n):
        bridges.append((arr1[i], arr2[i]))

    # Sort bridges by first bank and then by second bank
    bridges.sort()

    dp = [1] * n
    res = 1

    # Find Longest Non-Decreasing Subsequence
    for i in range(1, n):
        for j in range(i):
            if bridges[j][1] <= bridges[i][1]:
                dp[i] = max(dp[i], dp[j] + 1)

        res = max(res, dp[i])

    return res


if __name__ == "__main__":
    arr1 = [3, 1, 4, 4]
    arr2 = [1, 3, 2, 1]

    print(maxBridges(arr1, arr2))
C#
using System;
using System.Collections.Generic;

class GFG {
    public int maxBridges(int[] arr1, int[] arr2)
    {
        int n = arr1.Length;

        List<(int, int)> bridges = new List<(int, int)>();

        // Store all bridges
        for (int i = 0; i < n; i++) {
            bridges.Add((arr1[i], arr2[i]));
        }

        // Sort bridges by first bank and then by second
        // bank
        bridges.Sort();

        int[] dp = new int[n];
        Array.Fill(dp, 1);
        int res = 1;

        // Find Longest Non-Decreasing Subsequence
        for (int i = 1; i < n; i++) {
            for (int j = 0; j < i; j++) {
                if (bridges[j].Item2 <= bridges[i].Item2) {
                    dp[i] = Math.Max(dp[i], dp[j] + 1);
                }
            }

            res = Math.Max(res, dp[i]);
        }

        return res;
    }

    static void Main()
    {
        int[] arr1 = { 3, 1, 4, 4 };
        int[] arr2 = { 1, 3, 2, 1 };

        GFG obj = new GFG();

        Console.WriteLine(obj.maxBridges(arr1, arr2));
    }
}
JavaScript
function maxBridges(arr1, arr2)
{
    let n = arr1.length;

    let bridges = [];

    // Store all bridges
    for (let i = 0; i < n; i++) {
        bridges.push([ arr1[i], arr2[i] ]);
    }

    // Sort bridges by first bank and then by second bank
    bridges.sort((a, b) => {
        if (a[0] !== b[0]) {
            return a[0] - b[0];
        }
        return a[1] - b[1];
    });

    let dp = new Array(n).fill(1);
    let res = 1;

    // Find Longest Non-Decreasing Subsequence
    for (let i = 1; i < n; i++) {
        for (let j = 0; j < i; j++) {
            if (bridges[j][1] <= bridges[i][1]) {
                dp[i] = Math.max(dp[i], dp[j] + 1);
            }
        }

        res = Math.max(res, dp[i]);
    }

    return res;
}

// Driver code
let arr1 = [ 3, 1, 4, 4 ];
let arr2 = [ 1, 3, 2, 1 ];

console.log(maxBridges(arr1, arr2));

Output
3

[Expected Approach] Using Sorting with Binary Search (LNDS) - O(n log n) Time and O(n) Space

The idea is to first sort all the bridges by their first endpoints, and by their second endpoints in case of a tie. After sorting, any valid set of non-crossing bridges must have their second endpoints in non-decreasing order. Thus, the problem reduces to finding the Longest Non-Decreasing Subsequence (LNDS) of the second bank endpoints. The LNDS is computed efficiently using binary search (upper_bound()), and its length gives the maximum number of non-crossing bridges.

Let us understand with an example:
Input: arr1[] = [3, 1, 4, 4], arr2[] = [1, 3, 2, 1]

  • Form the bridge pairs: (3,1), (1,3), (4,2), (4,1).
  • Sort the pairs by the first endpoint (and second endpoint if tied) : (1,3), (3,1), (4,1), (4,2).
  • Consider the second endpoints: 3, 1, 1, 2.
  • Build the Longest Non-Decreasing Subsequence (LNDS) using binary search: [] -> [3] -> [1] -> [1,1] -> [1,1,2].
  • The length of the LNDS is 3, so the maximum number of non-crossing bridges is 3.
C++
#include <iostream>
#include <vector>
using namespace std;

int maxBridges(vector<int> &arr1, vector<int> &arr2)
{
    int n = arr1.size();

    vector<pair<int, int>> bridges;

    for (int i = 0; i < n; i++)
    {
        bridges.push_back({arr1[i], arr2[i]});
    }

    // Sort bridges by first bank and then by second bank
    sort(bridges.begin(), bridges.end());

    vector<int> res;

    for (auto &bridge : bridges)
    {
        int val = bridge.second;

        // Find position for LNDS using binary search
        auto idx = upper_bound(res.begin(), res.end(), val);

        if (idx == res.end())
        {
            res.push_back(val);
        }
        else
        {
            *idx = val;
        }
    }

    // Length of LNDS gives maximum non-crossing bridges
    return res.size();
}

int main()
{
    vector<int> arr1 = {3, 1, 4, 4};
    vector<int> arr2 = {1, 3, 2, 1};

    cout << maxBridges(arr1, arr2);

    return 0;
}
Java
import java.util.Arrays;
import java.util.ArrayList;

class GFG {

    public int maxBridges(int[] arr1, int[] arr2)
    {
        int n = arr1.length;

        int[][] bridges = new int[n][2];

        // Store corresponding bridge endpoints
        for (int i = 0; i < n; i++) {
            bridges[i][0] = arr1[i];
            bridges[i][1] = arr2[i];
        }

        // Sort bridges by first bank and then by second
        // bank
        Arrays.sort(bridges, (a, b) -> {
            if (a[0] != b[0]) {
                return Integer.compare(a[0], b[0]);
            }
            return Integer.compare(a[1], b[1]);
        });

        ArrayList<Integer> res = new ArrayList<>();

        for (int[] bridge : bridges) {
            int val = bridge[1];

            // Find position for LNDS using binary search
            int idx = upperBound(res, val);

            if (idx == res.size()) {
                res.add(val);
            }
            else {
                res.set(idx, val);
            }
        }

        // Length of LNDS gives maximum non-crossing
        // bridges
        return res.size();
    }

    private int upperBound(ArrayList<Integer> res, int val)
    {
        int left = 0, right = res.size();

        while (left < right) {
            int mid = left + (right - left) / 2;

            if (res.get(mid) <= val) {
                left = mid + 1;
            }
            else {
                right = mid;
            }
        }

        return left;
    }

    public static void main(String[] args)
    {
        int[] arr1 = { 3, 1, 4, 4 };
        int[] arr2 = { 1, 3, 2, 1 };

        GFG obj = new GFG();

        System.out.println(obj.maxBridges(arr1, arr2));
    }
}
Python
from bisect import bisect_right


def maxBridges(arr1, arr2):
    n = len(arr1)

    bridges = []

    # Store corresponding bridge endpoints.
    for i in range(n):
        bridges.append((arr1[i], arr2[i]))

    # Sort bridges by first bank and then by second bank.
    bridges.sort()

    res = []

    for bridge in bridges:
        val = bridge[1]

        # Find position for LNDS using binary search.
        idx = bisect_right(res, val)

        if idx == len(res):
            res.append(val)
        else:
            res[idx] = val

    # Length of LNDS gives maximum non-crossing bridges.
    return len(res)

if __name__ == "__main__":
    arr1 = [6, 4, 2, 1, 2]
    arr2 = [2, 3, 6, 5, 4]

    print(maxBridges(arr1, arr2))
C#
using System;
using System.Collections.Generic;

class GFG {
    public int maxBridges(int[] arr1, int[] arr2)
    {
        int n = arr1.Length;

        List<(int, int)> bridges = new List<(int, int)>();

        // Store corresponding bridge endpoints.
        for (int i = 0; i < n; i++) {
            bridges.Add((arr1[i], arr2[i]));
        }

        // Sort bridges by first bank and then by second
        // bank.
        bridges.Sort();

        List<int> res = new List<int>();

        foreach(var bridge in bridges)
        {
            int val = bridge.Item2;

            // Find position for LNDS using binary search.
            int idx = UpperBound(res, val);

            if (idx == res.Count) {
                res.Add(val);
            }
            else {
                res[idx] = val;
            }
        }

        // Length of LNDS gives maximum non-crossing
        // bridges.
        return res.Count;
    }

    private int UpperBound(List<int> res, int val)
    {
        int left = 0;
        int right = res.Count;

        while (left < right) {
            int mid = left + (right - left) / 2;

            if (res[mid] <= val) {
                left = mid + 1;
            }
            else {
                right = mid;
            }
        }

        return left;
    }

    static void Main()
    {
        int[] arr1 = { 3, 1, 4, 4 };
        int[] arr2 = { 1, 3, 2, 1 };

        GFG obj = new GFG();

        Console.WriteLine(obj.maxBridges(arr1, arr2));
    }
}
JavaScript
function maxBridges(arr1, arr2)
{
    const n = arr1.length;

    let bridges = [];

    for (let i = 0; i < n; i++) {
        bridges.push([ arr1[i], arr2[i] ]);
    }

    // Sort bridges by first bank and then by second bank.
    bridges.sort((a, b) => a[0] - b[0] || a[1] - b[1]);

    let res = [];

    for (const bridge of bridges) {
        const val = bridge[1];

        // Find position for LNDS using binary search.
        let idx = res.findIndex(x => x > val);
        if (idx === -1) {
            res.push(val);
        }
        else {
            res[idx] = val;
        }
    }

    // Length of LNDS gives maximum non-crossing bridges.
    return res.length;
}

// Driver Code
const arr1 = [ 3, 1, 4, 4 ];
const arr2 = [ 1, 3, 2, 1 ];

console.log(maxBridges(arr1, arr2));

Output
3
Comment