Java 如何找到位于同一直线上的最大点数

Java 如何找到位于同一直线上的最大点数,java,algorithm,plane,Java,Algorithm,Plane,假设在二维平面上有一个点阵列。点的定义如下: class Point { public int x; public int y; Point(int _x, int _y) { x = _x; y = _y; } } 如何在java中找到位于同一直线上的最大点数?对于阵列中的每个点,计算该点与其他点之间的角度。使用hashMap计算具有相同角度的数量。预计时间为^2 /** * Definition for a point. * struct Point {

假设在二维平面上有一个点阵列。点的定义如下:

class Point {
    public int x; 
    public int y;

    Point(int _x, int _y) { x = _x; y = _y; }
}

如何在java中找到位于同一直线上的最大点数?

对于阵列中的每个点,计算该点与其他点之间的角度。使用hashMap计算具有相同角度的数量。预计时间为^2

/**
 * Definition for a point.
 * struct Point {
 *     int x;
 *     int y;
 *     Point() : x(0), y(0) {}
 *     Point(int a, int b) : x(a), y(b) {}
 * };
 */
class Solution {
public:
    int maxPoints(vector<Point> &points) {
        int n = points.size(); //number of the points
        if (n<=2){return n;}   
        vector<double> k; //vector to store the slops for one point with all the other points
        int res = 0;

        for (int i=0;i<n;i++){ // for each point in the 2d plane
            k.clear();
            int dup = 1; // number of the duplicates with currrent point
            for (int j=0;j<n;j++){ 
                if (i!=j){ // for every other point
                    if (points[i].x-points[j].x==0){ // if the slope is a vertical line
                        if (points[i].y-points[j].y==0){ // if the point j is the same as point i
                            dup++;  
                        }else{
                            k.push_back(99999); //store the vertical line to a specific slope
                        }
                    }else{ // if it is the regular slop between point i and j
                        k.push_back(10000*(points[i].y-points[j].y)/(points[i].x-points[j].x)); // store the slope
                    }
                }
            }

            sort(k.begin(),k.end()); //sort the slopes for counting

            int pp = 1; //number of points in the same line of the point i
            if (k.size()==0){pp=0;} 

            for (int jj=1;jj<k.size();jj++){ //count pp
                if (k[jj]==k[jj-1]){
                    pp++;
                }else{
                    if (pp+dup>res){res=pp+dup;} // res = pp + the number of duplicates
                    pp = 1;
                }
            }
            if (pp+dup>res){res = pp+dup;}
        }

        return res;
    }
};
伪码

int result = 0;
for(int i = 0; i < data.length; i++){
    HashMap<Double, Integer> map = new HashMap();
    for(int j = 0; j < data.length; j++){
        if(i == j)
            continue;
        double angle = calculateAngle(data[i], data[j]);
        if(map.containsKey(slope)){
            map.put(angle, map.get(slope) + 1);
        }else{
            map.put(angle, 1);
        }
        result = max(result, map.get(slope));
    }
}

注意:正如NiklasB在评论中提到的,使用double将导致精度方面的一些问题,特别是当我们需要比较那些浮点值时。我们可以通过使用NiklasB建议的Rational类来避免这种情况。或者精度较低,对阵列中的每个点使用

,计算该点与其他点之间的角度。使用hashMap计算具有相同角度的数量。预计时间为^2

伪码

int result = 0;
for(int i = 0; i < data.length; i++){
    HashMap<Double, Integer> map = new HashMap();
    for(int j = 0; j < data.length; j++){
        if(i == j)
            continue;
        double angle = calculateAngle(data[i], data[j]);
        if(map.containsKey(slope)){
            map.put(angle, map.get(slope) + 1);
        }else{
            map.put(angle, 1);
        }
        result = max(result, map.get(slope));
    }
}

注意:正如NiklasB在评论中提到的,使用double将导致精度方面的一些问题,特别是当我们需要比较那些浮点值时。我们可以通过使用NiklasB建议的Rational类来避免这种情况。或者更不精确,使用

这里有一个使用精确算法的Java解决方案:

import java.util.List;
import java.util.Map;
import java.util.HashMap;

public class Solver {
    public int maxPointsOnLine(List<Point> points) {
        int ans = 0;
        Map<Line, Integer> lines = new HashMap<Line, Integer>();
        for (Point a : points) {
            int max = 0;
            int same = 0;
            lines.clear();

            for (Point b : points) {
                if (a.x == b.x && a.y == b.y) {
                    ++same;
                } else {
                    Line line = new Line(b.x - a.x, b.y - a.y);
                    Integer count = lines.get(line);
                    if (count == null) {
                        count = 0;
                    }
                    ++count;
                    lines.put(line, count);
                    max = Math.max(max, count);
                }
            }
            ans = Math.max(ans, same + max);
        }
        return ans;
    }

    static class Line {
        final int dx;
        final int dy;

        Line(int dx, int dy) {
            if (dy == 0) {
                dx = Math.abs(dx);
            }
            else if (dy < 0) {
                dx = -dx;
                dy = -dy;
            }
            int gcd = gcd(Math.abs(dx), dy);
            dx /= gcd;
            dy /= gcd;
            this.dx = dx;
            this.dy = dy;
        }

        @Override
        public boolean equals(Object other) {
            if (!(other instanceof Line)) {
                return false;
            }
            Line another = (Line)other;
            return dx == another.dy && dy == another.dy;
        }

        @Override
        public int hashCode() {
            return 31 * dx + dy;
        }
    }

    static int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
    }
}

以下是使用精确算法的Java解决方案:

import java.util.List;
import java.util.Map;
import java.util.HashMap;

public class Solver {
    public int maxPointsOnLine(List<Point> points) {
        int ans = 0;
        Map<Line, Integer> lines = new HashMap<Line, Integer>();
        for (Point a : points) {
            int max = 0;
            int same = 0;
            lines.clear();

            for (Point b : points) {
                if (a.x == b.x && a.y == b.y) {
                    ++same;
                } else {
                    Line line = new Line(b.x - a.x, b.y - a.y);
                    Integer count = lines.get(line);
                    if (count == null) {
                        count = 0;
                    }
                    ++count;
                    lines.put(line, count);
                    max = Math.max(max, count);
                }
            }
            ans = Math.max(ans, same + max);
        }
        return ans;
    }

    static class Line {
        final int dx;
        final int dy;

        Line(int dx, int dy) {
            if (dy == 0) {
                dx = Math.abs(dx);
            }
            else if (dy < 0) {
                dx = -dx;
                dy = -dy;
            }
            int gcd = gcd(Math.abs(dx), dy);
            dx /= gcd;
            dy /= gcd;
            this.dx = dx;
            this.dy = dy;
        }

        @Override
        public boolean equals(Object other) {
            if (!(other instanceof Line)) {
                return false;
            }
            Line another = (Line)other;
            return dx == another.dy && dy == another.dy;
        }

        @Override
        public int hashCode() {
            return 31 * dx + dy;
        }
    }

    static int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
    }
}


不可能在小于on的时间内解决^2@user3530447我们在这里讨论的是一组任意点吗?需要时间复杂度吗?如果取两个点,这两个点将始终显示在同一条线上,下一步是查看其他点是否“位于”这条线上。对所有点对执行此操作。这太慢了,我想它在^2上。这些点在2D平面上。@user3503447时间复杂度呢?@TejasPatel你能证明吗?不可能在少于On的时间内解决^2@user3530447我们在这里讨论的是一组任意点吗?需要时间复杂度吗?如果取两个点,这两个点将始终显示在同一条线上,下一步是查看其他点是否“位于”这条线上。对所有点对执行此操作。这太慢了,我想它在^2上。点在二维平面上。@user3503447时间复杂度呢?@TejasPatel你能证明吗?啊,这肯定会失败,因为浮点不精确。您必须存储一些标准化的整数分数。此外,您还需要能够处理两个以上点具有相同x坐标的情况。在这种情况下,斜率是无穷大。平行线怎么样。我会失败的too@TejasPatel平行线?这是从一个原点到其他点的斜率,而不是Ox或Oy轴:@NiklasB。是的,这里应该处理无穷大的情况,对于浮点,我们可以使用BigDecimal而不是double@PhamTrung不,BigDecimal不能表示有理数,这肯定会失败,因为浮点是不精确的。您必须存储一些标准化的整数分数。此外,您还需要能够处理两个以上点具有相同x坐标的情况。在这种情况下,斜率是无穷大。平行线怎么样。我会失败的too@TejasPatel平行线?这是从一个原点到其他点的斜率,而不是Ox或Oy轴:@NiklasB。是的,这里应该处理无穷大的情况,对于浮点,我们可以使用BigDecimal而不是double@PhamTrung不,BigDecimal不能表示有理数确定这适用于垂直线吗?顺便说一下,您可以使用PhamI提出的算法来摆脱Line类。我确信它对垂直线不起作用我编辑了我的答案,使用了线方程的一般形式。我几乎完全重写了我的解,使它更紧凑。@AlexYakunin是的,它适用于平行线。请注意,在每个最外层的迭代中,直线都是相对于点a的。确定这适用于垂直直线吗?顺便说一下,您可以使用PhamI提出的算法来摆脱Line类。我确信它对垂直线不起作用我编辑了我的答案,使用了线方程的一般形式。我几乎完全重写了我的解,使它更紧凑。@AlexYakunin是的,它适用于平行线。请注意,在每个最外层的迭代中,直线都是相对于点a的。