149. Max Points on a Line

原题链接

Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.

注意题目中给的点有可能是重复的。要统计哪条直线上的点最多,就一定要计算每两个点之间的直线,这是不可避免的,所以时间复杂度至少为O(n^2)。采用遍历的方法,当遍历第i个点时,只需计算它与第i+1个及之后的点的直线,这样避免了重复计算。

我最初的想法是用y=kx+b表示直线方程,然后记录每个(k,b)组合出现的次数,出现最多的那个组合表示的直线方程就是经过点最多的。出现次数可以用map<pair<double,double>, int>类型记录。这个方法有两个问题:第一,k表示斜率,但不是每两个点间的直线斜率都存在,所有垂直于x轴的直线都没有斜率,所以可能会出现被0除的错误;第二,题目给出的点坐标都是整数,计算k时会出现精度丢失的问题,可能出现两条斜率相近的直线被误认为相同的情况。

因为k=(y2-y1)/(x2-x1),为了解决上述两个问题,我不用k表示直线,而是直接用dy=y2-y1和dx=x2-x1表示。但是这样就要用dy、dx、b三个参数表示方程了,不能用map<pair, int>的数据结构了。b=y-kx,是由直线上的一个点和斜率决定的。如果我们在遍历每一个点时,都新建一个map记录每个(dy,dx)组合出现的次数,就可以省略b了,因为每条直线都会经过当前遍历的点,所以只要直线的dy、dx相同,它们的b值也必定相同。这样,在每个点遍历结束时,选出经过当前点的直线中包含点最多的那条,最后再在所有点的最值中选出包含点最多的直线。

/**
 * 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 nums = points.size();
        int x,y,gcd,duplicate;
        pair<int, int> p;
        int maxslope, maxline=0;
        
        for(int i=0; i<nums; i++) {
            duplicate = 1;
            maxslope = 0;
            map<pair<int,int>, int> count;
            for(int j=i+1; j<nums; j++) {
                y = points[j].y-points[i].y;
                x = points[j].x-points[i].x;
                if(x==0&&y==0) {
                    duplicate++;
                }
                else {
                    gcd = GCD(x,y);
                    x = x/gcd;
                    y = y/gcd;
                    p.first = x;
                    p.second = y;
                    count[p]++;
                    maxslope = max(maxslope, count[p]);
                }
            }
            maxline=max(maxline, maxslope+duplicate);
        }
        return maxline;
    }

 private:   
    int GCD(int a, int b) {
        if(b==0) return a;
        else return GCD(b, a%b);
    }
};

注意dx、dy(代码中的x、y)需要先用它们的最大公约数去除,再去map中查找。因为例如(1,1)、(2,2)、(3,3)三个点在同一直线上,(1,1)、(2,2)计算出的(dx,dy)是(1,1),(1,1)、(3,3)计算出的(dx,dy)是(2,2),如果不进行约分,就会认为这两条直线是不同的。

转载于:https://my.oschina.net/cofama/blog/894493

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值