题目地址:
https://leetcode.com/problems/maximum-number-of-visible-points/
给定平面直角坐标系的 n n n个点,再给定一个角度 a a a(范围 [ 0 , 360 ) [0,360) [0,360)),给定一个观察点,问该观察点张开角度 a a a最多能看到多少个点。有可能某个点恰好与观察点重合。
先求一下每个点与 x x x正方向所夹的角,可以用 arccos \arccos arccos来求,然后标准化一下(取 [ 0 , 2 π ) [0,2\pi) [0,2π)范围内),接着排序,由于张开的范围可能横跨 2 π 2\pi 2π,所以可以开个 2 n 2n 2n的数组循环存储,后面 n n n个点的角度增加 2 π 2\pi 2π。最后滑动窗口求一下最多能看到多少个点。代码如下:
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class Solution {
public int visiblePoints(List<List<Integer>> points, int angle, List<Integer> location) {
int cnt = 0;
double x = location.get(0), y = location.get(1);
List<Double> list = new ArrayList<>();
for (List<Integer> point : points) {
// 记录一下重合的
if (point.equals(location)) {
cnt++;
continue;
}
double x1 = point.get(0), y1 = point.get(1);
double acos = Math.acos((x1 - x) / Math.sqrt(pow2(x1 - x) + pow2(y1 - y)));
if (y1 < y) {
acos = 2 * Math.PI - acos;
}
list.add(acos);
}
double ang = angle / 180.0 * Math.PI;
list.sort(Double::compare);
int size = list.size();
for (int i = size; i < size * 2; i++) {
list.add(list.get(i - size) + 2 * Math.PI);
}
int res = cnt;
for (int i = 0, j = 0; i < list.size(); i++) {
while (j < list.size() && list.get(j) - list.get(i) <= ang) {
j++;
}
res = Math.max(res, cnt + j - i);
}
return res;
}
double pow2(double x) {
return x * x;
}
}
时间复杂度 O ( n log n ) O(n\log n) O(nlogn),空间 O ( n ) O(n) O(n)。