题目地址:
https://www.lintcode.com/problem/max-points-on-a-line/description
给定 n n n个二维平面里点的坐标,问最多有多少个点在同一条直线上。
时间 O ( n 2 ) O(n^2) O(n2)做法可以参考https://blog.csdn.net/qq_46105170/article/details/112557389。下面介绍朴素的 O ( n 3 ) O(n^3) O(n3)做法。
可以枚举其中两个位置不同的点(这里的意思是,有可能这些坐标有重复,而只有两个不同的点才能确定一条直线),然后看有多少个第三点位于前面两个点确定的直线上。为了容易枚举,我们可以将所有点进行排序(理论上可以按照任意全序关系进行排序,我们可以先按照 x x x坐标排序, x x x坐标一样就按 y y y坐标排序),这样位置相同的点将会紧挨着。此外要用到一个几何公式,三个点 ( x 1 , y 1 ) , ( x 2 , y 2 ) , ( x 3 , y 3 ) (x_1,y_1),(x_2,y_2),(x_3,y_3) (x1,y1),(x2,y2),(x3,y3)共线,等价于 ∣ x 1 x 2 x 3 y 1 y 2 y 3 1 1 1 ∣ = 0 \left|\begin{matrix} x_1 & x_2 & x_3 \\ y_1 & y_2 & y_3\\ 1 & 1 & 1 \end{matrix}\right| =0 ∣∣∣∣∣∣x1y11x2y21x3y31∣∣∣∣∣∣=0可以想象在三维空间中,如果三个点 ( x 1 , y 1 , 1 ) , ( x 2 , y 2 , 1 ) , ( x 3 , y 3 , 1 ) (x_1,y_1,1),(x_2,y_2,1),(x_3,y_3,1) (x1,y1,1),(x2,y2,1),(x3,y3,1)和原点 ( 0 , 0 , 0 ) (0,0,0) (0,0,0)的张成的棱锥体积为 0 0 0,那么 ( x 1 , y 1 ) , ( x 2 , y 2 ) , ( x 3 , y 3 ) (x_1,y_1),(x_2,y_2),(x_3,y_3) (x1,y1),(x2,y2),(x3,y3)一定共线。代码如下:
import java.util.Arrays;
public class Solution {
/**
* @param points: an array of point
* @return: An integer
*/
public int maxPoints(Point[] points) {
// write your code here
if (points == null || points.length == 0) {
return 0;
}
// 先对所有的点排序,使得位置相同的点紧挨着
Arrays.sort(points, (p1, p2) -> p1.x != p2.x ? Integer.compare(p1.x, p2.x) : Integer.compare(p1.y, p2.y));
int res = 0;
for (int i = 0; i < points.length; i++) {
int duplicate = 1;
Point p1 = points[i];
if (i > 0 && equal(p1, points[i - 1])) {
continue;
}
for (int j = i + 1; j < points.length; j++) {
Point p2 = points[j];
// 遇到和p1位置相同的点,则略过,因为这时候p1和p2不能确定一条直线
if (equal(p1, p2)) {
duplicate++;
continue;
}
// 走到这里说明发现了与p1不同的点,此时p1和p2能确定一条直线,数一下别的点里有多少个点在此直线上
int count = 0;
for (int k = j + 1; k < points.length; k++) {
Point p3 = points[k];
if ((p1.x * p2.y - p1.y * p2.x) - (p1.x * p3.y - p1.y * p3.x) + (p2.x * p3.y - p2.y * p3.x) == 0) {
count++;
}
}
// duplicate指的是和p1位置相同的点,1是指的p2,count是p3的可能数目
res = Math.max(res, duplicate + 1 + count);
}
// 这里要考虑一下p1之后的点都与p1重合的情况
res = Math.max(res, duplicate);
}
return res;
}
private boolean equal(Point p1, Point p2) {
return p1.x == p2.x && p1.y == p2.y;
}
}
class Point {
int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
}
时间复杂度 O ( n 3 ) O(n^3) O(n3),空间 O ( 1 ) O(1) O(1)。