Maximum Number of Visible Points

HARD

Description

You are given an array points, an integer angle, and your location, where location = [posx, posy] and points[i] = [xi, yi] both denote integral coordinates on the X-Y plane.

Initially, you are facing directly east from your position. You cannot move from your position, but you can rotate. In other words, posx and posy cannot be changed. Your field of view in degrees is represented by angle, determining how wide you can see from any given view direction. Let d be the amount in degrees that you rotate counterclockwise. Then, your field of view is the inclusive range of angles [d - angle/2, d + angle/2].

You can see some set of points if, for each point, the angle formed by the point, your position, and the immediate east direction from your position is in your field of view.

There can be multiple points at one coordinate. There may be points at your location, and you can always see these points regardless of your rotation. Points do not obstruct your vision to other points.

Return the maximum number of points you can see.

 

Example 1:

Input: points = [[2,1],[2,2],[3,3]], angle = 90, location = [1,1]
Output: 3
Explanation: The shaded region represents your field of view. All points can be made visible in your field of view, including [3,3] even though [2,2] is in front and in the same line of sight.

Example 2:

Input: points = [[2,1],[2,2],[3,4],[1,1]], angle = 90, location = [1,1]
Output: 4
Explanation: All points can be made visible in your field of view, including the one at your location.

Example 3:

Input: points = [[1,0],[2,1]], angle = 13, location = [1,1]
Output: 1
Explanation: You can only see one of the two points, as shown above.

 

Constraints:

  • 1 <= points.length <= 105
  • points[i].length == 2
  • location.length == 2
  • 0 <= angle < 360
  • 0 <= posx, posy, xi, yi <= 100

Approaches

Checkout 2 different approaches to solve Maximum Number of Visible Points. Click on different approaches to view the approach and algorithm in detail.

Sliding Window on Sorted Circular Angles

This is an optimized approach that avoids the O(N^2) complexity. It involves calculating the angle for each point, sorting these angles, and then using a sliding window technique to find the maximum number of points that can fit within the given angle range. The circular nature of angles is handled by duplicating the angle list.

Algorithm

    1. Separate points at the observer's location from other points. Count them in pointsAtLocation.
    1. For each point not at the location, calculate its angle relative to the observer using Math.atan2, convert to degrees, and normalize to [0, 360).
    1. Store these angles in a list.
    1. Sort the list of angles in ascending order.
    1. To handle the circular nature of angles, create a new extended list. This list contains the original sorted angles followed by a copy of each angle with 360 added to it.
    1. Initialize two pointers, start = 0 and end = 0, for the sliding window, and maxPoints = 0.
    1. Iterate with the end pointer from the beginning to the end of the extended list.
    1. Inside the loop, move the start pointer forward as long as the angular distance between the points at end and start is greater than the given angle (angles.get(end) - angles.get(start) > angle).
    1. The current number of points in the window is end - start + 1. Update maxPoints = max(maxPoints, end - start + 1).
    1. After the loop, the final answer is maxPoints + pointsAtLocation.

Similar to the first approach, we first handle points at the observer's location and calculate the angles for all other points, normalizing them to [0, 360). The key insight is that if we sort the angles, we can efficiently find the number of points in any given angular range.

The problem is on a circle, so a view window might "wrap around" from 360 to 0 degrees (e.g., from 350 to 20 degrees). To handle this easily, we create an extended list of angles. We take our sorted list of angles a1, a2, ..., aN and append a second copy of each angle incremented by 360: a1+360, a2+360, ..., aN+360. This transforms the circular problem into a linear one.

Now, we can apply a sliding window (two-pointer) approach on this new, extended list. We use a start pointer and an end pointer, both initialized to the beginning. We iterate the end pointer through the extended list. For each position of end, we advance the start pointer until the angle at start is within the allowed angle degrees from the angle at end (i.e., angles.get(end) - angles.get(start) <= angle). The number of points in the current valid window is end - start + 1. We keep track of the maximum window size found. This maximum size is the maximum number of points visible in any single rotation. We add the count of points at the observer's location to get the final answer.

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

class Solution {
    public int visiblePoints(List<List<Integer>> points, int angle, List<Integer> location) {
        List<Double> angles = new ArrayList<>();
        int pointsAtLocation = 0;
        int locX = location.get(0);
        int locY = location.get(1);

        for (List<Integer> p : points) {
            int pX = p.get(0);
            int pY = p.get(1);
            if (pX == locX && pY == locY) {
                pointsAtLocation++;
            } else {
                angles.add(calculateAngle(locY, locX, pY, pX));
            }
        }

        Collections.sort(angles);

        // To handle wrap-around, duplicate the angles array with +360
        List<Double> circularAngles = new ArrayList<>(angles);
        for (double ang : angles) {
            circularAngles.add(ang + 360.0);
        }

        int maxPoints = 0;
        if (angles.isEmpty()) {
            return pointsAtLocation;
        }

        int start = 0;
        for (int end = 0; end < circularAngles.size(); end++) {
            while (circularAngles.get(end) - circularAngles.get(start) > angle) {
                start++;
            }
            maxPoints = Math.max(maxPoints, end - start + 1);
        }

        return maxPoints + pointsAtLocation;
    }

    private double calculateAngle(int y1, int x1, int y2, int x2) {
        double angleRad = Math.atan2(y2 - y1, x2 - x1);
        double angleDeg = Math.toDegrees(angleRad);
        if (angleDeg < 0) {
            angleDeg += 360;
        }
        return angleDeg;
    }
}

Complexity Analysis

Time Complexity: O(N log N), where N is the number of points not at the observer's location. The sorting step is the bottleneck. Calculating angles takes O(N), and the sliding window part takes O(N) as each pointer traverses the list only once.Space Complexity: O(N), where N is the number of points not at the observer's location. Space is needed for the initial angles list and the extended list for the sliding window.

Pros and Cons

Pros:
  • Highly efficient with O(N log N) time complexity, suitable for large inputs.
  • The sliding window on a duplicated array is a standard and elegant technique for circular array problems.
Cons:
  • Requires extra O(N) space for the duplicated list of angles.
  • Slightly more complex to conceptualize and implement compared to the brute-force solution.

Code Solutions

Checking out 3 solutions in different languages for Maximum Number of Visible Points. Click on different languages to view the code.

class Solution { public int visiblePoints ( List < List < Integer >> points , int angle , List < Integer > location ) { List < Double > v = new ArrayList <>(); int x = location . get ( 0 ), y = location . get ( 1 ); int same = 0 ; for ( List < Integer > p : points ) { int xi = p . get ( 0 ), yi = p . get ( 1 ); if ( xi == x && yi == y ) { ++ same ; continue ; } v . add ( Math . atan2 ( yi - y , xi - x )); } Collections . sort ( v ); int n = v . size (); for ( int i = 0 ; i < n ; ++ i ) { v . add ( v . get ( i ) + 2 * Math . PI ); } int mx = 0 ; Double t = angle * Math . PI / 180 ; for ( int i = 0 , j = 0 ; j < 2 * n ; ++ j ) { while ( i < j && v . get ( j ) - v . get ( i ) > t ) { ++ i ; } mx = Math . max ( mx , j - i + 1 ); } return mx + same ; } }

Video Solution

Watch the video walkthrough for Maximum Number of Visible Points



Algorithms:

Sorting

Patterns:

MathSliding WindowGeometry

Data Structures:

Array

Subscribe to Scale Engineer newsletter

Learn about System Design, Software Engineering, and interview experiences every week.

No spam, unsubscribe at any time.