【Lintcode】186. Max Points on a Line

题目地址:

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)

猜你喜欢

转载自blog.csdn.net/qq_46105170/article/details/112556694