Open In App

Find Maximum Number of Intersections on the Chart

Last Updated : 11 May, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

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:


drdrawio

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:

Java
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
Python
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))
JavaScript
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));
C++14
#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)



Like Article
Suggest improvement
Previous
Next
Share your thoughts in the comments

Similar Reads