LeetCode-Max Points on a Line-最大共线的点的数目-Hash

题目见

https://oj.leetcode.com/problems/max-points-on-a-line/

如果使用叉乘对每根线检查所有顶点,妥妥的超时。

看了别人答案,发现这道题有如下O(n^2)算法:

对每个点i:

1)检查它与[i+1,n)点组成的线,如果有两根线斜率一样,那么这两根线是同一根。

2)对所有点统计,求出每个点出发的线的最多共线的个数。

这样枚举了(n-1)+(n-2)+...1个点,并且所有的线都没有漏掉。

还需要注意的是斜率最好用整数方法保存,通过除掉最大公约数,再将符号统一化,而不要使用浮点数提高精度。

/**
 * Definition for a point.
 * struct Point {
 *     int x;
 *     int y;
 *     Point() : x(0), y(0) {}
 *     Point(int a, int b) : x(a), y(b) {}
 * };
 */
typedef pair<int,int> scpair;
class Solution {
public:
    int n,m;
    vector <Point> points;
    int gcd(int a,int b){
        if (a<b){return gcd(b,a);}
        if (b==0){return a;}
        return gcd(b,a%b);
    }
    scpair CalcTan(int p1,int p2){
        int y=points[p2].y-points[p1].y;
        int x=points[p2].x-points[p1].x;
        int g=gcd(abs(y),abs(x));
        if (g==0){ return scpair(x,y);}
        int a=x/g;
        int b=y/g;
        if (a * b <0){  
            a=-abs(a);
            b=abs(b);
        }
        else{
            a=abs(a);
            b=abs(b);
        }
        return scpair(a,b);
        
    }
    int maxPoints(vector<Point> &points) {
        this->points=points;
        n=points.size();
        if (n<3){return n;}
        int res=numeric_limits<int>::min();
        for (int i=0;i<n-1;i++) {
            map <scpair,int> s;
            int rep=0;
            for (int j=i+1;j<n;j++){
                scpair t=CalcTan(i,j);
                if (t==scpair(0,0)){rep++;continue;}
                if (s.count(t)==0){s[t]=1;}
                else {s[t]++;}
            }
            res=max(res,rep);
            for (map<scpair,int>::iterator it=s.begin();it!=s.end();it++ ){
                res=max(res,it->second+rep);
            }
        }
        return res+1;
    }
};

 

posted @ 2014-09-30 16:03  zombies  阅读(302)  评论(0编辑  收藏  举报