Open In App

Maximum intersection of a horizontal lines with a vertical

Last Updated : 27 Mar, 2025
Comments
Improve
Suggest changes
Like Article
Like
Report

Given n horizontal line segments are arranged on the X-axis of a 2D plane. The start and end point of each line segment is given in an nx2 matrix lines[ ][ ], the task is to find the maximum number of intersections possible of any vertical line with the given n line segments.

Examples:

Input: n = 4, lines[][] = [ [ 1, 3 ], [ 2, 3], [ 1, 2 ], [ 4, 4 ] ]
Output: 3
Explanation: A vertical line at X = 2 passes through {1, 3}, {2, 3}, {1, 2}, i.e. three of the given horizontal lines.

Input: n= 3, lines[][] = [ [ 1, 3 ], [ 5, 6 ], [ 3, 4 ] ]
Output: 2
Explanation: A vertical line at X = 3 passes through two of the given horizontal lines which are the maximum possible.

This problem is mainly a variation of popular problem called Minimum Platforms.

[Naive Approach] Using Nested Loop â€“ O(n*m) Time and O(1) Space

This approach is based on independently checking the count of every x-axis point that it lies across how many line segments.

  • Identify the Range of Vertical Lines: Determine the minimum and maximum x-coordinates from the start and end points of all line segments to define the valid range for vertical lines.
  • Check Intersections for Each Vertical Line: For each vertical line within the valid range, check how many line segments intersect with it by comparing the x-coordinate with the start and end points of the segments.
  • Track Maximum Intersections: Keep track of the maximum number of line segments that intersect with any vertical line and return this value as the result.
C++
#include <bits/stdc++.h>
using namespace std;

int maxIntersec(vector<vector<int>>& lines) {
    int n = lines.size(), maxInt = 0;
    int minX = INT_MAX, maxX = INT_MIN;
    for (auto& line : lines) {
        minX = min(minX, line[0]);
        maxX = max(maxX, line[1]);
    }

    for (int x = minX; x <= maxX; ++x) {
        int cnt = 0;
        for (auto& line : lines) {
            
             // Check if line intersects vertical line at x
            if (line[0] <= x && x <= line[1]) 
                cnt++;
        }
        maxInt = max(maxInt, cnt); 
    }
    return maxInt;
}

int main() {
    vector<vector<int>> lines = {{1, 3}, {5, 6}, {3, 4}};
    cout << maxIntersec(lines) << endl;  
    return 0;
}
Java
import java.util.*;

public class GFG {
    public static int maxIntersec(List<int[]> lines) {
        int maxInt = 0, minX = Integer.MAX_VALUE, maxX = Integer.MIN_VALUE;
        for (int[] line : lines) {
            minX = Math.min(minX, line[0]);
            maxX = Math.max(maxX, line[1]);
        }

        for (int x = minX; x <= maxX; ++x) {
            int cnt = 0;
            for (int[] line : lines) {
                
                // Check if line intersects vertical line at x
                if (line[0] <= x && x <= line[1]) 
                    cnt++;
            }
            maxInt = Math.max(maxInt, cnt);
        }
        return maxInt;
    }

    public static void main(String[] args) {
        List<int[]> lines = Arrays.asList(new int[]{1, 3}, new int[]{2, 3}, new int[]{1, 2}, new int[]{4, 4});
        System.out.println(maxIntersec(lines));  
    }
}
Python
def maxIntersec(lines):
    maxInt, minX, maxX = 0, float('inf'), float('-inf')
    for line in lines:
        minX = min(minX, line[0])
        maxX = max(maxX, line[1])

    for x in range(minX, maxX + 1):
        cnt = 0
        for line in lines:
            #   Check if line intersects vertical line at x
            if line[0] <= x <= line[1]:
                cnt += 1
        maxInt = max(maxInt, cnt)
    return maxInt


lines = [[1, 3], [2, 3], [1, 2], [4, 4]]
print(maxIntersec(lines))  
C#
using System;
using System.Collections.Generic;

class GFG {
    public static int maxIntersec(List<int[]> lines) {
        int maxInt = 0, minX = int.MaxValue, maxX = int.MinValue;
        foreach (var line in lines) {
            minX = Math.Min(minX, line[0]);
            maxX = Math.Max(maxX, line[1]);
        }

        for (int x = minX; x <= maxX; ++x) {
            int cnt = 0;
            foreach (var line in lines) {
                // Check if line intersects vertical line at x
                if (line[0] <= x && x <= line[1])
                    cnt++;
            }
            maxInt = Math.Max(maxInt, cnt);
        }
        return maxInt;
    }

    static void Main() {
        var lines = new List<int[]> { new int[] { 1, 3 }, new int[] { 2, 3 }, new int[] { 1, 2 }, new int[] { 4, 4 } };
        Console.WriteLine(maxIntersec(lines));
    }
}
JavaScript
function maxIntersec(lines) {
    let maxInt = 0, minX = Number.POSITIVE_INFINITY, maxX = Number.NEGATIVE_INFINITY;
    for (let line of lines) {
        minX = Math.min(minX, line[0]);
        maxX = Math.max(maxX, line[1]);
    }

    for (let x = minX; x <= maxX; ++x) {
        let cnt = 0;
        for (let line of lines) {
             // Check if line intersects vertical line at x
            if (line[0] <= x && x <= line[1]) 
                cnt++;
        }
        maxInt = Math.max(maxInt, cnt);
    }
    return maxInt;
}


let lines = [[1, 3], [2, 3], [1, 2], [4, 4]];
console.log(maxIntersec(lines));  

Output
2

Time complexity is O(n*m) where n is the size of list and m is the difference between the max and min x points.

[Better Approach] Using Sorting and Two Pointer – O(n log n) Time and O(n) Space

In this approach, we first sort the start and end points of the line segments. We then use two pointers: one for the start points and one for the end points. If the start point is less than or equal to the end point, it means a new line is starting, so we increase the count of intersections. If the start point is greater than the end point, it means a line has ended, so we decrease the intersection count. At each step, we check and update the maximum number of intersections. This method efficiently tracks the intersections without having to check every single point on the x-axis.

  • Sort Start and End Points: The start and end points of all the line segments are sorted to efficiently process the intersections.
  • Two Pointer Technique: Traverse through the sorted start and end points using two pointers. Increment the intersection count when a new line starts and decrement when a line ends.
  • Track Maximum Intersections: Continuously update the maximum number of active intersections during the traversal and return the result.
C++
#include <bits/stdc++.h>
using namespace std;

int maxIntersec(vector<vector<int>>& lines, int n) {
    vector<int> start(n), end(n);
    
    for (int i = 0; i < n; ++i) {
        start[i] = lines[i][0];
        end[i] = lines[i][1];
    }
    sort(start.begin(), start.end());
    sort(end.begin(), end.end());
    
    int i = 0, j = 0, intersect = 0, maxInter = 0;
   
    while (i < n && j < n) {
        
        // If the next line starts before the current one ends
        if (start[i] <= end[j]) {
            intersect++;
            maxInter = max(maxInter, intersect);
            i++;
        }
        
        // If a line ends before the next line starts,
        else {
            intersect--;
            j++;
        }
    }
    
    return maxInter;
}

int main() {
    int n = 4;
    vector<vector<int>> lines = {{1, 3}, {2, 3}, {1, 2}, {4, 4}};
    
    cout << maxIntersec(lines, n) << endl;  
    
    return 0;
}
Java
import java.util.*;

public class GFG {
    public static int maxIntersec(List<int[]> lines) {
        int n = lines.size();
        int[] start = new int[n], end = new int[n];
        
        for (int i = 0; i < n; ++i) {
            start[i] = lines.get(i)[0];
            end[i] = lines.get(i)[1];
        }
        
        Arrays.sort(start);
        Arrays.sort(end);
        
        int i = 0, j = 0, intersect = 0, maxInter = 0;
        
        while (i < n && j < n) {
            if (start[i] <= end[j]) {
                intersect++;
                maxInter = Math.max(maxInter, intersect);
                i++;
            } else {
                intersect--;
                j++;
            }
        }
        
        return maxInter;
    }

    public static void main(String[] args) {
        List<int[]> lines = Arrays.asList(new int[]{1, 3}, new int[]{2, 3}, new int[]{1, 2}, new int[]{4, 4});
        System.out.println(maxIntersec(lines)); 
    }
}
Python
def maxIntersec(lines):
    n = len(lines)
    start = [lines[i][0] for i in range(n)]
    end = [lines[i][1] for i in range(n)]
    
    start.sort()
    end.sort()
    
    i, j, intersect, maxInter = 0, 0, 0, 0
    
    while i < n and j < n:
        if start[i] <= end[j]:
            intersect += 1
            maxInter = max(maxInter, intersect)
            i += 1
        else:
            intersect -= 1
            j += 1
    
    return maxInter

lines = [[1, 3], [2, 3], [1, 2], [4, 4]]
print(maxIntersec(lines)) 
C#
using System;
using System.Collections.Generic;

class Program {
    public static int maxIntersec(List<int[]> lines) {
        int n = lines.Count;
        int[] start = new int[n], end = new int[n];
        
        for (int k = 0; k < n; ++k) {
            start[k] = lines[k][0];
            end[k] = lines[k][1];
        }
        
        Array.Sort(start);
        Array.Sort(end);
        
        int i = 0, j = 0, intersect = 0, maxInter = 0;
        
        while (i < n && j < n) {
            if (start[i] <= end[j]) {
                intersect++;
                maxInter = Math.Max(maxInter, intersect);
                i++;
            } else {
                intersect--;
                j++;
            }
        }
        
        return maxInter;
    }

    static void Main() {
        var lines = new List<int[]> { new int[] { 1, 3 }, new int[] { 2, 3 }, new int[] { 1, 2 }, new int[] { 4, 4 } };
        Console.WriteLine(maxIntersec(lines));  
    }
}
JavaScript
function maxIntersec(lines) {
    const n = lines.length;
    const start = lines.map(line => line[0]);
    const end = lines.map(line => line[1]);
    
    start.sort((a, b) => a - b);
    end.sort((a, b) => a - b);
    
    let i = 0, j = 0, intersect = 0, maxInter = 0;
    
    while (i < n && j < n) {
        if (start[i] <= end[j]) {
            intersect++;
            maxInter = Math.max(maxInter, intersect);
            i++;
        } else {
            intersect--;
            j++;
        }
    }
    
    return maxInter;
}


const lines = [[1, 3], [2, 3], [1, 2], [4, 4]];
console.log(maxIntersec(lines));  

Output
3


[Expected Approach] Using Hash Map – O(n) Time and O(n) Space

Instead of checking all x-axis points, we focus only on the start and end points of the line segments. We use a map to track these points: incrementing the count when a line starts and decrementing it when a line ends. After processing all points, we simply check the map to find the point with the highest count, which gives the maximum number of intersections. This method is efficient as we only consider the relevant points.

  • Create Events: Treat the start of a line as an increment and the end (adjusted by +1) as a decrement to track active line segments.
  • Use of Map: Store events in a sorted map where keys are x-coordinates and values are the count of active lines.
  • Process Events: Traverse the events, updating the active count at each x-coordinate and track the maximum intersections.
C++
#include <bits/stdc++.h>
using namespace std;

int maxIntersec(vector<vector<int>>& lines) {
    unordered_map<int, int> events;

    // Create events for each line segment
    for (auto& line : lines) {
        events[line[0]]++;   
        events[line[1] + 1]--; 
    }

    int cnt = 0, maxCnt = 0;

    for (auto& event : events) {
        cnt += event.second;  
        maxCnt = max(maxCnt, cnt);  
    }
    return maxCnt;
}

int main() {
    vector<vector<int>> lines = {{1, 3}, {5, 6}, {3, 4}};
    cout << maxIntersec(lines) << endl; 
    return 0;
}
Java
import java.util.*;

public class GFG {
    public static int maxIntersec(List<int[]> lines) {
        Map<Integer, Integer> events = new HashMap<>();

        // Create events for each line segment
        for (int[] line : lines) {
            events.put(line[0], events.getOrDefault(line[0], 0) + 1);
            events.put(line[1] + 1, events.getOrDefault(line[1] + 1, 0) - 1);
        }

        int cnt = 0, maxCnt = 0;

        for (int value : events.values()) {
            cnt += value;
            maxCnt = Math.max(maxCnt, cnt);
        }
        return maxCnt;
    }

    public static void main(String[] args) {
        List<int[]> lines = Arrays.asList(new int[]{1, 3}, new int[]{5, 6}, new int[]{3, 4});
        System.out.println(maxIntersec(lines));  
    }
}
Python
def maxIntersec(lines):
    events = {}

    # Create events for each line segment
    for line in lines:
        events[line[0]] = events.get(line[0], 0) + 1
        events[line[1] + 1] = events.get(line[1] + 1, 0) - 1

    cnt, maxCnt = 0, 0

    for value in events.values():
        cnt += value
        maxCnt = max(maxCnt, cnt)
        
    return maxCnt

lines = [[1, 3], [5, 6], [3, 4]]
print(maxIntersec(lines))  
C#
using System;
using System.Collections.Generic;

class Program {
    public static int maxIntersec(List<int[]> lines) {
        Dictionary<int, int> events = new Dictionary<int, int>();

        // Create events for each line segment
        foreach (var line in lines) {
         
            if (!events.ContainsKey(line[0]))
                events[line[0]] = 0;
            events[line[0]]++;

            if (!events.ContainsKey(line[1] + 1))
                events[line[1] + 1] = 0;
            events[line[1] + 1]--;
        }

        int cnt = 0, maxCnt = 0;

       
        foreach (var eventCount in events.Values) {
            cnt += eventCount; 
            maxCnt = Math.Max(maxCnt, cnt);  
        }

        return maxCnt;
    }

    static void Main() {
        var lines = new List<int[]> { new int[] { 1, 3 }, new int[] { 5, 6 }, new int[] { 3, 4 } };
        Console.WriteLine(maxIntersec(lines));  
    }
}
JavaScript
function maxIntersec(lines) {
    let events = {};

    // Create events for each line segment
    for (let line of lines) {
        events[line[0]] = (events[line[0]] || 0) + 1;
        events[line[1] + 1] = (events[line[1] + 1] || 0) - 1;
    }

    let cnt = 0, maxCnt = 0;

    for (let value of Object.values(events)) {
        cnt += value;
        maxCnt = Math.max(maxCnt, cnt);
    }
    
    return maxCnt;
}

const lines = [[1, 3], [5, 6], [3, 4]];
console.log(maxIntersec(lines));

Output
2

Next Article
Article Tags :
Practice Tags :

Similar Reads