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; } };