# Find minimum y coordinates from set of N lines in a plane

• Last Updated : 15 Sep, 2022

Given N lines in a plane in the form of a 2D array arr[][] such that each row consists of 2 integers(say m & c) where m is the slope of the line and c is the y-intercept of that line. You are given Q queries each consist of x-coordinates. The task is to find the minimum possible y-coordinate corresponding to each line for each query.
Examples:

Input: arr[][] = { { 4, 0 }, { -3, 0 }, { 5, 1 }, { 3, -1 },{ 2, 3 }, { 1, 4 } } and Q[] = {-6, 3, 100}
Output:
-29
-9
-300
Explanation:
The minimum value for x = -6 from the given set of lines is -29.
The minimum value for x = 3 from the given set of lines is -9.
The minimum value for x = -100 from the given set of lines is -300.

Naive Approach: The naive approach is to find the y-coordinates for each line and the minimum of all the y-coordinates will give the minimum y-coordinate value. Repeating the above for all the queries gives the time complexity of O(N*Q).
Efficient Approach:
Observations 1. L1 an L2 are two lines and they intersect at (x1, y1), if L1 is lower than before x = x1 then L2 will be lower than L1 after x = x1. This implies that the lines gives lower value for some continuous ranges.
2. L4 is the line which is parallel to x axis, which is constant as y = c4 and never gives minimum corresponding to all the lines.
3. Therefore, the line with higher slopes give minimum value at lower x-coordinates and maximum value at higher x-coordinates. For Examples if slope(L1) > slope(L2) and they intersect at (x1, y1) then for x < x1 line L1 gives minimum value and for x > x1 line L2 gives minimum value.
4. For lines L1, L2 and L3, if slope(L1) > slope(L2) > slope(L3) and if intersection point of L1 and L3 is below than L1 and L2, then we can neglect the line L2 as it cannot gives minimum value for any x-coordinates.

On the basis of the above observations following are the steps:

1. Sort the slopes in decreasing order of slope.
2. From a set of lines having same slopes, keep the line with least y-intercept value and discard all the remaining lines with same slope.
3. Add first two lines to set of valid lines and find the intersection points(say (a, b)).
4. For the next set of remaining lines do the following:
• Find the intersection point(say (c, d)) of the second last line and the current line.
• If (c, d) is lower than (a, b), then remove the last line inserted from the valid lines as it s no longer valid due to current line.
5. Repeat the above steps to generate all the valid lines set.
6. Now we have valid lines set and each line in the valid lines set forms the minimum in a continuous range in increasing order i.e., L1 is minimum in range [a, b] and L2 in range [b, c].
7. Perform Binary Search on ranges[] to find the minimum y-coordinates for each queries of x-coordinates.

Below is the implementation of the above approach:

## CPP

 `// C++ program for the above approach``#include ``using` `namespace` `std;` `// To store the valid lines``vector > lines;` `// To store the distinct lines``vector > distinct;` `// To store the ranges of intersection``// points``vector > ranges;` `// Function that returns the intersection``// points``pair<``int``, ``int``> intersection(pair<``int``, ``int``> a,``                            ``pair<``int``, ``int``> b)``{``    ``int` `x = a.second - b.second;``    ``int` `y = b.first - a.first;``    ``return` `{ x, y };``}` `// Function to see if a line is eligible``// or not.``// L3 is the current line being added and``// we check eligibility of L2``bool` `isleft(pair<``int``, ``int``> l1,``            ``pair<``int``, ``int``> l2,``            ``pair<``int``, ``int``> l3)``{``    ``pair<``int``, ``int``> x1, x2;` `    ``// Find intersections``    ``x1 = intersection(l1, l3);``    ``x2 = intersection(l1, l2);` `    ``// Returns true if x1 is left of x2``    ``return` `(x1.first * x2.second``            ``< x2.first * x1.second);``}` `// Comparator function to sort the line[]``bool` `cmp(pair<``int``, ``int``> a, pair<``int``, ``int``> b)``{``    ``if` `(a.first != b.first)``        ``return` `a.first > b.first;``    ``else``        ``return` `a.second < b.second;``}` `// Find x-coordinate of intersection``// of 2 lines``int` `xintersect(pair<``int``, ``int``> a,``               ``pair<``int``, ``int``> b)``{` `    ``int` `A = a.second - b.second;``    ``int` `B = b.first - a.first;` `    ``// Find the x coordinate``    ``int` `x = A / B;` `    ``if` `(A * B < 0)``        ``x -= 1;` `    ``return` `x;``}` `// Function to returns the minimum``// possible value for y``int` `findy(vector >& ranges,``          ``int` `pt)``{``    ``int` `lo = 0, hi = ranges.size() - 1;``    ``int` `mid = 0;` `    ``// Binary search to find the minimum``    ``// value``    ``while` `(lo <= hi) {` `        ``// Find middle element``        ``mid = (lo + hi) / 2;` `        ``if` `(ranges[mid].first <= pt``            ``&& ranges[mid].second >= pt) {``            ``break``;``        ``}``        ``else` `if` `(ranges[mid].first > pt) {``            ``hi = mid - 1;``        ``}``        ``else` `{``            ``lo = mid + 1;``        ``}``    ``}` `    ``// Returns the minimum value``    ``return` `lines[mid].first * pt + lines[mid].second;``}` `// Function to add a valid line and``// remove the invalid lines``void` `add(pair<``int``, ``int``> x)``{``    ``// Add the current line``    ``lines.push_back(x);` `    ``// While Loop``    ``while` `(lines.size() >= 3``           ``&& isleft(lines[lines.size() - 3],``                     ``lines[lines.size() - 2],``                     ``lines[lines.size() - 1])) {` `        ``// Erase invalid lines``        ``lines.erase(lines.end() - 2);``    ``}``}` `// Function to updateLines on the``// basis of distinct slopes``void` `updateLines(pair<``int``, ``int``> line[],``                 ``int` `n)``{` `    ``// Sort the line according to``    ``// decreasing order of slope``    ``sort(line, line + n, cmp);` `    ``// To track for last slope``    ``int` `lastslope = INT_MIN;` `    ``// Traverse the line[] and find``    ``// set of distinct lines``    ``for` `(``int` `i = 0; i < n; i++) {` `        ``if` `(line[i].first == lastslope)``            ``continue``;` `        ``// Push the current line in``        ``// array distinct[]``        ``distinct.push_back(line[i]);` `        ``// Update the last slope``        ``lastslope = line[i].first;``    ``}` `    ``// Traverse the distinct[] and``    ``// update the valid lines to lines[]``    ``for` `(``int` `i = 0; i < distinct.size(); i++)``        ``add(distinct[i]);` `    ``int` `left = INT_MIN;``    ``int` `i, right = 0;` `    ``// Traverse the valid lines array``    ``for` `(i = 0; i < lines.size() - 1; i++) {` `        ``// Find the intersection point``        ``int` `right = xintersect(lines[i],``                               ``lines[i + 1]);` `        ``// Insert the current intersection``        ``// points in ranges[]``        ``ranges.push_back({ left, right });` `        ``left = right + 1;``    ``}` `    ``ranges.push_back({ left, INT_MAX });``}` `// Driver Code``int` `main()``{``    ``int` `n = 6;` `    ``// Set of lines of slopes and y intercept``    ``pair<``int``, ``int``> line[] = { { 4, 0 }, { -3, 0 },``                              ``{ 5, 1 }, { 3, -1 },``                              ``{ 2, 3 }, { 1, 4 } };` `    ``// Function Call``    ``updateLines(line, n);` `    ``// Queries for x-coordinates``    ``int` `Q[] = { -6, 3, 100 };` `    ``// Traverse Queries to find minimum``    ``// y-coordinates``    ``for` `(``int` `i = 0; i < 3; i++) {` `        ``// Use Binary Search in ranges``        ``// to find the minimum y-coordinates``        ``cout << findy(ranges, Q[i])``             ``<< endl;``    ``}``    ``return` `0;``}`

## Python3

 `# Python 3 program for the above approach` `# To store the valid lines``lines ``=` `[]` `# To store the distinct lines``distinct ``=` `[]` `# To store the ranges of intersection``# points``ranges ``=` `[]` `# Function that returns the intersection``# points`  `def` `intersection(a, b):``    ``x ``=` `a[``1``] ``-` `b[``1``]``    ``y ``=` `b[``0``] ``-` `a[``0``]``    ``return` `x, y`  `# Function to see if a line is eligible``# or not.``# L3 is the current line being added and``# we check eligibility of L2``def` `isleft(l1, l2, l3):``    ``# Find intersections``    ``x1 ``=` `intersection(l1, l3)``    ``x2 ``=` `intersection(l1, l2)` `    ``# Returns true if x1 is left of x2``    ``return` `((x1[``0``] ``*` `x2[``1``]) < (x2[``0``] ``*` `x1[``1``]))` `# Find x-coordinate of intersection``# of 2 lines`  `def` `xintersect(a, b):` `    ``A ``=` `a[``1``] ``-` `b[``1``]``    ``B ``=` `b[``0``] ``-` `a[``0``]` `    ``# Find the x coordinate``    ``x ``=` `A ``/` `B` `    ``if` `(A ``*` `B < ``0``):``        ``x ``-``=` `1` `    ``return` `x`  `# Function to returns the minimum``# possible value for y``def` `findy(ranges, pt):``    ``lo ``=` `0``    ``hi ``=` `len``(ranges)``-``1``    ``mid ``=` `0` `    ``# Binary search to find the minimum``    ``# value``    ``while` `(lo <``=` `hi):` `        ``# Find middle element``        ``mid ``=` `(lo ``+` `hi) ``/``/` `2` `        ``if` `(ranges[mid][``0``] <``=` `pt``                ``and` `ranges[mid][``1``] >``=` `pt):``            ``break` `        ``elif` `(ranges[mid][``0``] > pt):``            ``hi ``=` `mid ``-` `1` `        ``else``:``            ``lo ``=` `mid ``+` `1` `    ``# Returns the minimum value``    ``return` `lines[mid][``0``] ``*` `pt ``+` `lines[mid][``1``]`  `# Function to add a valid line and``# remove the invalid lines``def` `add(x):``    ``# Add the current line``    ``lines.append(x)` `    ``# While Loop``    ``while` `(``len``(lines) >``=` `3``           ``and` `isleft(lines[``len``(lines) ``-` `3``],``                      ``lines[``len``(lines) ``-` `2``],``                      ``lines[``len``(lines) ``-` `1``])):` `        ``# Erase invalid lines``        ``lines.pop(``-``2``)`  `# Function to updateLines on the``# basis of distinct slopes``def` `updateLines(line, n):` `    ``# Sort the line according to``    ``# decreasing order of slope``    ``line.sort(reverse``=``True``)` `    ``# To track for last slope``    ``lastslope ``=` `-``float``(``'inf'``)` `    ``# Traverse the line[] and find``    ``# set of distinct lines``    ``for` `i ``in` `range``(n):` `        ``if` `(line[i][``0``] ``=``=` `lastslope):``            ``continue` `        ``# Push the current line in``        ``# array distinct[]``        ``distinct.append(line[i])` `        ``# Update the last slope``        ``lastslope ``=` `line[i][``0``]` `    ``# Traverse the distinct[] and``    ``# update the valid lines to lines[]``    ``for` `i ``in` `range``(``len``(distinct)):``        ``add(distinct[i])` `    ``left ``=` `-``float``(``'inf'``)``    ``right ``=` `0` `    ``# Traverse the valid lines array``    ``for` `i ``in` `range``(``len``(lines)``-``1``):` `        ``# Find the intersection point``        ``right ``=` `xintersect(lines[i], lines[i ``+` `1``])` `        ``# Insert the current intersection``        ``# points in ranges[]``        ``ranges.append((left, right))` `        ``left ``=` `right ``+` `1` `    ``ranges.append((left, ``float``(``'inf'``)))`  `# Driver Code``if` `__name__ ``=``=` `'__main__'``:``    ``n ``=` `6` `    ``# Set of lines of slopes and y intercept``    ``line ``=` `[(``4``, ``0``), (``-``3``, ``0``),``            ``(``5``, ``1``), (``3``, ``-``1``),``            ``(``2``, ``3``), (``1``, ``4``)]` `    ``# Function Call``    ``updateLines(line, n)` `    ``# Queries for x-coordinates``    ``Q ``=` `[ ``-``6``, ``3``, ``100``]` `    ``# Traverse Queries to find minimum``    ``# y-coordinates``    ``for` `i ``in` `range``(``3``):` `        ``# Use Binary Search in ranges``        ``# to find the minimum y-coordinates``        ``print``(findy(ranges, Q[i]))`

## Javascript

 `// JS program for the above approach` `// To store the valid lines``let lines = []` `// To store the distinct lines``let distinct = []` `// To store the ranges of intersection``// points``let ranges = []` `// Function that returns the intersection``// points`  `function` `intersection(a, b)``{``    ``let x = a - b``    ``let y = b - a``    ``return` `[x, y]``}`  `// Function to see if a line is eligible``// or not.``// L3 is the current line being added and``// we check eligibility of L2``function` `isleft(l1, l2, l3)``{``    ``// Find intersections``    ``let x1 = intersection(l1, l3)``    ``let x2 = intersection(l1, l2)` `    ``// Returns true if x1 is left of x2``    ``return` `((x1 * x2) < (x2 * x1))``}` `// Find x-coordinate of intersection``// of 2 lines`  `function` `xintersect(a, b)``{``    ``let A = a - b``    ``let B = b - a` `    ``// Find the x coordinate``    ``let x = A / B` `    ``if` `(A * B < 0)``        ``x -= 1` `    ``return` `x``}`  `// Function to returns the minimum``// possible value for y``function` `findy(ranges, pt)``{``    ``let lo = 0``    ``let hi = (ranges).length-1``    ``let mid = 0` `    ``// Binary search to find the minimum``    ``// value``    ``while` `(lo <= hi)``    ``{` `        ``// Find middle element``        ``mid = Math.floor((lo + hi) / 2)` `        ``if` `(ranges[mid] <= pt``                ``&& ranges[mid] >= pt)``            ``break` `        ``else` `if` `(ranges[mid] > pt)``            ``hi = mid - 1` `        ``else``            ``lo = mid + 1``    ``}` `    ``// Returns the minimum value``    ``return` `lines[mid] * pt + lines[mid]``}`  `// Function to add a valid line and``// remove the invalid lines``function` `add(x)``{``    ``// Add the current line``    ``lines.push(x)` `    ``// While Loop``    ``while` `((lines).length >= 3``           ``&& isleft(lines[(lines).length - 3],``                      ``lines[(lines).length - 2],``                      ``lines[(lines).length - 1]))` `        ``// Erase invalid lines``        ``lines.splice(lines.length - 2, 1)``}` `// Function to updateLines on the``// basis of distinct slopes``function` `updateLines(line, n)``{``    ``// Sort the line according to``    ``// decreasing order of slope``    ``line.sort(``function``(a , b)``    ``{``        ``return` `a > b;``    ``})` `    ``// To track for last slope``    ``let lastslope = -Infinity;` `    ``// Traverse the line[] and find``    ``// set of distinct lines``    ``for` `(``var` `i = 0; i < n; i++)``    ``{``        ``if` `(line[i] == lastslope)``            ``continue` `        ``// Push the current line in``        ``// array distinct[]``        ``distinct.push(line[i])` `        ``// Update the last slope``        ``lastslope = line[i]``    ``}``    ` `    ``// Traverse the distinct[] and``    ``// update the valid lines to lines[]``    ``for` `(``var` `i = 0; i < distinct.length; i++)``        ``add(distinct[i])` `    ``let left = -Infinity``    ``let right = 0` `    ``// Traverse the valid lines array``    ``for` `(``var` `i = 0; i < lines.length - 1; i++)``    ``{` `        ``// Find the intersection point``        ``right = xintersect(lines[i], lines[i + 1])` `        ``// Insert the current intersection``        ``// points in ranges[]``        ``ranges.push((left, right))` `        ``left = right + 1``    ``}` `    ``ranges.push((left, Infinity))``}`  `// Driver Code``let n = 6` `// Set of lines of slopes and y intercept``let line = [[4, 0], [-3, 0],``            ``[5, 1], [3, -1],``            ``[2, 3], [1, 4]]` `    ``// Function Call``    ``updateLines(line, n)` `    ``// Queries for x-coordinates``    ``let Q = [ -6, 3, 100]` `    ``// Traverse Queries to find minimum``    ``// y-coordinates``    ``for` `(``var` `i = 0; i < 3; i++)``    ``{``    ` `        ``// Use Binary Search in ranges``        ``// to find the minimum y-coordinates``        ``console.log(findy(ranges, Q[i]))``    ``}``    ` `   ``// This code is contributed by phasing17`

Output:

```-29
-9
-300```

Time Complexity: O(N + Q*log N), where N is the number of lines and Q is the numbers of queries
Auxiliary Space: O(N)

My Personal Notes arrow_drop_up