2Brute2Best
🔥0

Building Bridges

Medium·GeeksforGeeksBasic Anchor
GeeksforGeeks
30-Second Mental ModelDP — LIS, 2D / envelopes (sort by one side, then a non-decreasing run on the other)
Complexity:O(2^N)→O(N log N)
Key Insight

Sort by north (ties by south). Keep tails[k] = the smallest south end that finishes a run of k + 1 bridges. For a new bridge with south end s, find the first tail bigger than s with binary search. Replace that tail with s. If no tail is bigger than s, append s. The answer is the number of tails.

Core Validity Invariant

A bridge with south end s can extend a run only when the run's last south end is not higher than s, so the longest run it can extend is the one that the upper_bound search finds.

01

Problem

Picture a river with cities on both banks. Each city on the north bank is paired with one city on the south bank by index: north[i] can only be joined to south[i]. A bridge joins north[i] → south[i].

You want as many bridges as possible, with no two bridges crossing. Two bridges cross when one starts further left on the north bank but ends further right on the south bank. Bridges that start or end at the same x-coordinate do not cross.

Return the largest number of bridges you can build.

Input

Two lists of the same length n: north and south. Bridge i joins north[i] to south[i].

Output

The largest number of bridges that can be built with no crossing.

Example 1
Input: north = [6, 4, 2, 1], south = [2, 3, 6, 5]
Output: 2

The bridges 2 → 6 and 1 → 5 do not cross, and they can be built together. No set of three bridges works without a crossing.

Example 2
Input: north = [8, 1, 4, 3, 5, 2, 6, 7], south = [1, 2, 3, 4, 5, 6, 7, 8]
Output: 5

The bridges 1 → 2, 3 → 4, 5 → 5, 6 → 7 and 7 → 8 all go up on both banks, so none of them cross.

Constraints
  • • Both lists have the same length `n`. No other limits are given.
02

First, think yourself

Before opening any solution, try to answer these on paper. Use hints only when stuck — each hint is counted.

  1. 1.

    Two bridges cross when their order is flipped on the two banks. Which order do I need to keep on both banks?

  2. 2.

    If I sort the bridges by their north end, what must the south ends do so that no two bridges cross?

  3. 3.

    Does the order of the input lists matter for the answer? What happens if I look at the south ends in the order they were given?

  4. 4.

    Can two bridges share the same north x-coordinate? If they do, what order should their south ends be in?

  5. 5.

    This looks like the Longest Increasing Subsequence. What changes about the word 'increasing' here?

03

Brute force approach

04

Better approach

05

Optimized approach

06

Why does this algorithm work?

07

Dry run

08

All approaches compared

ApproachIdeaTimeSpace
Brute ForceSort by north, then try keep or skip for each bridge; keep a bridge only if its south end is not lower than the last one keptO(2^N)O(N)
Betterdp[i] = most bridges in a run that ends at bridge i; check every earlier bridge whose south end is not higherO(N²)O(N)
OptimalSort by north; keep tails[k] = smallest south end of a run of k + 1 bridges; binary search each new south endO(N log N)O(N)
09

Why does this belong to this pattern?

Clues in the problem statement
  • “cities paired by index”Each bridge is one pair (north, south). Sort the pairs as a whole. Do not sort the two lists separately.
  • “no two bridges cross”After sorting by north, the south ends must never go down. That is a rule on one list, so the 2D problem becomes a 1D one.
  • “maximum number of bridges”We want the longest valid run, so the answer is a length, which `tails` gives directly.
Sort by one side (north, ties by south)+longest run where the other side never goes down+maximum count→DP — LIS, 2D / envelopes (sort by one side, then a non-decreasing run on the other)

The sort turns a 2D rule into a 1D one: after sorting by north, bridges are valid exactly when their south ends never go down. Ties on north are sorted by south, so bridges that share a north end can all be kept. The key difference from Classic LIS is that equal values are allowed, so the search uses upper_bound. Best Team With No Conflicts uses the same sort-then-run idea, but adds a score to each run.

10

Don't make this mistake

Pattern confusion: running the LIS on the list in input order
✗ // no sort: walk the pairs in the order they were given for (auto& p : pairs) { /* tails + upper_bound on p.second */ }
✓ sort(pairs.begin(), pairs.end()); // by north first, then the run on south

The input order is not the order of the north ends, so a run of south values can jump across bridges that cross. On the first example the south values in input order are 2, 3, 6, 5. The run 2, 3, 6 has length 3, so this code returns 3. But the bridges 6 → 2 and 2 → 6 cross each other, so the right answer is 2.

Equal north ends sorted the wrong way
✗ sort(pairs.begin(), pairs.end(), [](auto& a, auto& b) { return a.first != b.first ? a.first < b.first : a.second > b.second; });
✓ sort(pairs.begin(), pairs.end()); // ties on north: smaller south first

Two bridges that start at the same north end do not cross, so both can be kept. Sorting ties with the south end descending puts the bigger south first, and the run can then keep only one of them. On north = [3, 3] and south = [7, 2] the right answer is 2, but this code returns 1.

Strict comparison: lower_bound instead of upper_bound
✗ auto it = lower_bound(tails.begin(), tails.end(), p.second);
✓ auto it = upper_bound(tails.begin(), tails.end(), p.second);

Two bridges that end at the same south city do not cross, so the second can follow the first. On north = [1, 2] and south = [5, 5], the right answer is 2. lower_bound replaces the 5 instead of adding a new run, so it returns 1.

11

Want to implement this?

Write it yourself on GeeksforGeeks, then come back and compare your code with the solutions above.

Open coding workspace
How did it go?
Beyond The LeetCode Problem

How this concept connects to System Design & C++ Systems

Bridge DSA with production engineering

Top engineering interviews test whether you understand how algorithms like DP — Longest Increasing Subsequence translate into production architectures and low-level memory mechanics.