题目
给定一个二维平面及平面上的 N 个点列表Points
,其中第i
个点的坐标为Points[i]=[X
i,Y
i]
。请找出一条直线,其通过的点的数目最多。
设穿过最多点的直线所穿过的全部点编号从小到大排序的列表为S
,你仅需返回[S[0],S[1]]
作为答案,若有多条直线穿过了相同数量的点,则选择S[0]
值较小的直线返回,S[0]
相同则选择S[1]
值较小的直线返回。
示例:
输入: [[0,0],[1,1],[1,0],[2,0]]
输出: [0,2]
解释: 所求直线穿过的3个点的编号为[0,2,3]
1
2
3
2
3
提示:
2 <= len(Points) <= 300
len(Points[i]) = 2
题解
java
public int[] bestLine(int[][] points) {
// 第1、2位为索引 第3位为经过点的数量
Map<String, int[]> lines = new HashMap<>(8);
// 最大公约数
BiFunction<Integer, Integer, Integer> gcd = new BiFunction<Integer, Integer, Integer>() {
@Override
public Integer apply(Integer a, Integer b) {
return b == 0 ? a : this.apply(b, a % b);
}
};
// 直线公式 A*x + B*y + C = 0 返回 A、B、C list
BiFunction<int[], int[], String> line = (p1, p2) -> {
int x1 = p1[0], y1 = p1[1], x2 = p2[0], y2 = p2[1];
int x0 = x2 - x1, y0 = y2 - y1;
int a = y0, b = -x0, c = x0 * y1 - y0 * x1;
// 若A、B、C存在公约数
int g = gcd.apply(gcd.apply(a, b), c);
a /= g;
b /= g;
c /= g;
// 生成方程式的key
return String.format("%d_%d_%d", a, b, c);
};
// 缓存最大
AtomicReference<int[]> max = new AtomicReference<>(new int[]{0, 1, 2});
for (int i = 1; i < points.length; i++) {
// 从小到大 保证第一次出现的为小索引到大索引
for (int j = 0; j < i; j++) {
lines.merge(line.apply(points[i], points[j]), new int[]{j, i, 2}, (o, n) -> {
// 若已存在一条直线 则累加点数量
o[2]++;
// 存数量最多 索引位置较小的
if (o[2] > max.get()[2] || (o[2] == max.get()[2] && o[0] < max.get()[0])) {
max.set(o);
}
return o;
});
}
}
return Arrays.copyOfRange(max.get(), 0, 2);
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42