Find Maximum Number of Intersections on the Chart
Given a line chart with n points connected by line segments and a 1-indexed integer array y[], where the ith point has coordinates (i, y[i]). There are no horizontal lines, meaning no two consecutive points have the same y-coordinate. The task is to find the maximum number of points of intersection of an infinitely long horizontal line with the chart.
Example:
Input: y = [1,2,1,2,1,3,2]
Output: 5
Explanation: As you can see in the image above, the line y = 1.5 has 5 intersections with the chart (in red crosses). You can also see the line y = 2 which intersects the chart in 4 points (in red crosses). It can be shown that there is no horizontal line intersecting the chart at more than 5 points. So the answer would be 5.Input: y = [2,1,3,4,5]
Output: 2
Explanation: As you can see in the image above, the line y = 1.5 has 2 intersections with the chart (in red crosses). You can also see the line y = 2 which intersects the chart in 2 points (in red crosses). It can be shown that there is no horizontal line intersecting the chart at more than 2 points. So the answer would be 2.
Approach:
Create and ordered map of + and – with the coordinates. Then we can sweep through the map from least to greatest while keeping a running sum which is equal to the number of intersections of a horizontal line at the current y coordinate.
Trick is to multiply each number by 2 to create space after each number; we need this if we want to avoid using floating points, because for example, if we have test case {2,1,3}, we need to have a -1 between 2 and 3.
Steps to solve this problem:
- Multiply each element in vector ‘y’ by 2 to create spaces between numbers.
- Create a map to store the count of each y-coordinate.
- Initialize the previous slope to 0.
- Add the first y-coordinate to the map with a count of 1, and the next y-coordinate with a count of -1.
- Iterate over the remaining y-coordinates:
- Calculate the slope between the current and previous y-coordinates.
- If the slope has changed and the previous slope was not 0:
- If the slope is positive, increment the count of the y-coordinate at the bottom of the valley and decrement the count of the y-coordinate at the top of the valley.
- If the slope is negative, decrement the count of the y-coordinate at the bottom of the hill and increment the count of the y-coordinate at the top of the hill.
- If the slope remains the same:
- If the slope is negative, decrement the count of the y-coordinate at the top of the line and increment the count of the y-coordinate at the bottom of the line.
- If the slope is positive, increment the count of the y-coordinate at the top of the line and decrement the count of the y-coordinate at the bottom of the line.
- Update the previous slope.
- Initialize the answer to -1 and current count to 0.
- Iterate over the map and update the answer to the maximum of the current answer and the current count.
- Return the answer.
Below is the Implementation of above approach:
import java.util.HashMap;
import java.util.Map;
public class MaxIntersectionCount {
public static int maxIntersectionCount(int[] y)
{
// Multiply each element in y by 2 to create spaces
// between numbers. This is done to avoid dealing
// with floating point numbers when calculating
// slopes.
for (int i = 0; i < y.length; i++) {
y[i] *= 2;
}
// Create a map to store the count of each
// y-coordinate.
Map<Integer, Integer> ys = new HashMap<>();
// Initialize the previous slope to 0.
int prev_dy = 0;
// Add the first y-coordinate to the map with a
// count of 1.
ys.put(y[0], 1);
// Add the next y-coordinate to the map with a count
// of -1. This is done to create a "valley" between
// the first two points.
ys.put(y[0] + 1, -1);
// Iterate over the remaining y-coordinates.
for (int i = 1; i < y.length; i++) {
// Calculate the slope between the current and
// previous y-coordinates.
int dy = y[i] < y[i - 1] ? -1 : 1;
// If the slope has changed and the previous
// slope was not 0, then we have encountered a
// valley or a hill.
if (prev_dy != dy && prev_dy != 0) {
// If the slope is positive, then we have
// encountered a valley.
if (dy > 0) {
// Increment the count of the
// y-coordinate at the bottom of the
// valley.
ys.put(y[i - 1] + 1,
ys.getOrDefault(y[i - 1] + 1, 0)
+ 1);
// Decrement the count of the
// y-coordinate at the top of the
// valley.
ys.put(y[i] + 1,
ys.getOrDefault(y[i] + 1, 0)
- 1);
}
// Otherwise, we have encountered a hill.
else {
// Decrement the count of the
// y-coordinate at the bottom of the
// hill.
ys.put(y[i - 1],
ys.getOrDefault(y[i - 1], 0)
- 1);
// Increment the count of the
// y-coordinate at the top of the hill.
ys.put(y[i],
ys.getOrDefault(y[i], 0) + 1);
}
}
// Otherwise, we have encountered a straight
// line.
else {
// If the slope is negative, then we are
// going down.
if (dy < 0) {
// Decrement the count of the
// y-coordinate at the top of the line.
ys.put(y[i - 1],
ys.getOrDefault(y[i - 1], 0)
- 1);
// Increment the count of the
// y-coordinate at the bottom of the
// line.
ys.put(y[i],
ys.getOrDefault(y[i], 0) + 1);
}
// Otherwise, we are going up.
else {
// Increment the count of the
// y-coordinate at the top of the line.
ys.put(y[i - 1] + 1,
ys.getOrDefault(y[i - 1] + 1, 0)
+ 1);
// Decrement the count of the
// y-coordinate at the bottom of the
// line.
ys.put(y[i] + 1,
ys.getOrDefault(y[i] + 1, 0)
- 1);
}
}
// Update the previous slope.
prev_dy = dy;
}
// Initialize the answer to -1.
int answer = -1;
// Initialize the current count to 0.
int curr = 0;
// Iterate over the map.
for (Map.Entry<Integer, Integer> entry :
ys.entrySet()) {
// Add the count of the current y-coordinate to
// the current count.
curr += entry.getValue();
// Update the answer to the maximum of the
// current answer and the current count.
answer = Math.max(answer, curr);
}
// Return the answer.
return answer;
}
public static void main(String[] args)
{
int[] y = { 1, 2, 1, 2, 1, 3, 2 };
System.out.println(maxIntersectionCount(y));
}
}
// This code is contributed by shivamgupta0987654321
def max_intersection_count(y):
# Multiply each element in y by 2 to create spaces
# between numbers. This is done to avoid dealing
# with floating point numbers when calculating slopes.
y = [i * 2 for i in y]
# Create a dictionary to store the count of each
# y-coordinate.
ys = {}
# Initialize the previous slope to 0.
prev_dy = 0
# Add the first y-coordinate to the dictionary with a
# count of 1.
ys[y[0]] = 1
# Add the next y-coordinate to the dictionary with a count
# of -1. This is done to create a "valley" between
# the first two points.
ys[y[0] + 1] = -1
# Iterate over the remaining y-coordinates.
for i in range(1, len(y)):
# Calculate the slope between the current and
# previous y-coordinates.
dy = -1 if y[i] < y[i - 1] else 1
# If the slope has changed and the previous
# slope was not 0, then we have encountered a
# valley or a hill.
if prev_dy != dy and prev_dy != 0:
# If the slope is positive, then we have
# encountered a valley.
if dy > 0:
# Increment the count of the
# y-coordinate at the bottom of the
# valley.
ys[y[i - 1] + 1] = ys.get(y[i - 1] + 1, 0) + 1
# Decrement the count of the
# y-coordinate at the top of the
# valley.
ys[y[i] + 1] = ys.get(y[i] + 1, 0) - 1
# Otherwise, we have encountered a hill.
else:
# Decrement the count of the
# y-coordinate at the bottom of the
# hill.
ys[y[i - 1]] = ys.get(y[i - 1], 0) - 1
# Increment the count of the
# y-coordinate at the top of the
# hill.
ys[y[i]] = ys.get(y[i], 0) + 1
# Otherwise, we have encountered a straight
# line.
else:
# If the slope is negative, then we are
# going down.
if dy < 0:
# Decrement the count of the
# y-coordinate at the top of the line.
ys[y[i - 1]] = ys.get(y[i - 1], 0) - 1
# Increment the count of the
# y-coordinate at the bottom of the
# line.
ys[y[i]] = ys.get(y[i], 0) + 1
# Otherwise, we are going up.
else:
# Increment the count of the
# y-coordinate at the top of the line.
ys[y[i - 1] + 1] = ys.get(y[i - 1] + 1, 0) + 1
# Decrement the count of the
# y-coordinate at the bottom of the
# line.
ys[y[i] + 1] = ys.get(y[i] + 1, 0) - 1
# Update the previous slope.
prev_dy = dy
# Initialize the answer to -1.
answer = -1
# Initialize the current count to 0.
curr = 0
# Iterate over the dictionary.
for value in ys.values():
# Add the count of the current y-coordinate to
# the current count.
curr += value
# Update the answer to the maximum of the
# current answer and the current count.
answer = max(answer, curr)
# Return the answer.
return answer
# Main method to test the code
if __name__ == "__main__":
y = [1, 2, 1, 2, 1, 3, 2]
print(max_intersection_count(y))
function maxIntersectionCount(y) {
// Multiply each element in y by 2 to create spaces
// between numbers. This is done to avoid dealing
// with floating point numbers when calculating
// slopes.
for (let i = 0; i < y.length; i++) {
y[i] *= 2;
}
// Create a map to store the count of each
// y-coordinate.
let ys = new Map();
// Initialize the previous slope to 0.
let prev_dy = 0;
// Add the first y-coordinate to the map with a
// count of 1.
ys.set(y[0], 1);
// Add the next y-coordinate to the map with a count
// of -1. This is done to create a "valley" between
// the first two points.
ys.set(y[0] + 1, -1);
// Iterate over the remaining y-coordinates.
for (let i = 1; i < y.length; i++) {
// Calculate the slope between the current and
// previous y-coordinates.
let dy = y[i] < y[i - 1] ? -1 : 1;
// If the slope has changed and the previous
// slope was not 0, then we have encountered a
// valley or a hill.
if (prev_dy !== dy && prev_dy !== 0) {
// If the slope is positive, then we have
// encountered a valley.
if (dy > 0) {
// Increment the count of the
// y-coordinate at the bottom of the
// valley.
ys.set(y[i - 1] + 1, (ys.get(y[i - 1] + 1) || 0) + 1);
// Decrement the count of the
// y-coordinate at the top of the
// valley.
ys.set(y[i] + 1, (ys.get(y[i] + 1) || 0) - 1);
}
// Otherwise, we have encountered a hill.
else {
// Decrement the count of the
// y-coordinate at the bottom of the
// hill.
ys.set(y[i - 1], (ys.get(y[i - 1]) || 0) - 1);
// Increment the count of the
// y-coordinate at the top of the hill.
ys.set(y[i], (ys.get(y[i]) || 0) + 1);
}
}
// Otherwise, we have encountered a straight
// line.
else {
// If the slope is negative, then we are
// going down.
if (dy < 0) {
// Decrement the count of the
// y-coordinate at the top of the line.
ys.set(y[i - 1], (ys.get(y[i - 1]) || 0) - 1);
// Increment the count of the
// y-coordinate at the bottom of the
// line.
ys.set(y[i], (ys.get(y[i]) || 0) + 1);
}
// Otherwise, we are going up.
else {
// Increment the count of the
// y-coordinate at the top of the line.
ys.set(y[i - 1] + 1, (ys.get(y[i - 1] + 1) || 0) + 1);
// Decrement the count of the
// y-coordinate at the bottom of the
// line.
ys.set(y[i] + 1, (ys.get(y[i] + 1) || 0) - 1);
}
}
// Update the previous slope.
prev_dy = dy;
}
// Initialize the answer to -1.
let answer = -1;
// Initialize the current count to 0.
let curr = 0;
// Iterate over the map.
for (let [key, value] of ys.entries()) {
// Add the count of the current y-coordinate to
// the current count.
curr += value;
// Update the answer to the maximum of the
// current answer and the current count.
answer = Math.max(answer, curr);
}
// Return the answer.
return answer;
}
let y = [1, 2, 1, 2, 1, 3, 2];
console.log(maxIntersectionCount(y));
#include <bits/stdc++.h>
using namespace std;
int maxIntersectionCount(vector<int>& y)
{
// Multiply each element in y by 2 to create spaces
// between numbers. This is done to avoid dealing with
// floating point numbers when calculating slopes.
for (int& i : y) {
i *= 2;
}
// Create a map to store the count of each y-coordinate.
map<int, int> ys;
// Initialize the previous slope to 0.
int prev_dy = 0;
// Add the first y-coordinate to the map with a count
// of 1.
ys[y[0]] = 1;
// Add the next y-coordinate to the map with a count of
// -1. This is done to create a "valley" between the
// first two points.
ys[y[0] + 1] = -1;
// Iterate over the remaining y-coordinates.
for (int i = 1; i < y.size(); ++i) {
// Calculate the slope between the current and
// previous y-coordinates.
int dy = y[i] < y[i - 1] ? -1 : 1;
// If the slope has changed and the previous slope
// was not 0, then we have encountered a valley or a
// hill.
if (prev_dy != dy && prev_dy) {
// If the slope is positive, then we have
// encountered a valley.
if (dy > 0) {
// Increment the count of the y-coordinate
// at the bottom of the valley.
++ys[y[i - 1] + 1];
// Decrement the count of the y-coordinate
// at the top of the valley.
--ys[y[i] + 1];
}
// Otherwise, we have encountered a hill.
else {
// Decrement the count of the y-coordinate
// at the bottom of the hill.
--ys[y[i - 1]];
// Increment the count of the y-coordinate
// at the top of the hill.
++ys[y[i]];
}
}
// Otherwise, we have encountered a straight line.
else {
// If the slope is negative, then we are going
// down.
if (dy < 0) {
// Decrement the count of the y-coordinate
// at the top of the line.
--ys[y[i - 1]];
// Increment the count of the y-coordinate
// at the bottom of the line.
++ys[y[i]];
}
// Otherwise, we are going up.
else {
// Increment the count of the y-coordinate
// at the top of the line.
++ys[y[i - 1] + 1];
// Decrement the count of the y-coordinate
// at the bottom of the line.
--ys[y[i] + 1];
}
}
// Update the previous slope.
prev_dy = dy;
}
// Initialize the answer to -1.
int answer = -1;
// Initialize the current count to 0.
int curr = 0;
// Iterate over the map.
for (auto& it : ys) {
auto v = it.second;
// Add the count of the current y-coordinate to the
// current count.
curr += v;
// Update the answer to the maximum of the current
// answer and the current count.
answer = max(answer, curr);
}
// Return the answer.
return answer;
}
int main()
{
vector<int> y = { 1, 2, 1, 2, 1, 3, 2 };
cout << maxIntersectionCount(y) << endl;
return 0;
}
Output
5
Time complexity: O(nlog(n))
Space complexity: O(n)