对于含有一系列坐标点的向量,求此平面上某直线最多的点的数目。
由平面几何知识:一个初始点+方向可以确定一条直线,故分两重循环:
第一重是初始点a
第二重是剩余的某点b,由b:
b与a重合,则a所在的所有的直线上的点都加1
b不与a重合,则构成一个方向,方向由斜率表示(对于垂直方向斜率无穷故单独考虑)且该方向上点数目加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) {}
* };
*/
class Solution {
public:
int maxPoints(vector<Point>& points){
if(points.empty())return 0;
if(points.size()==1)return 1;
int res=0;
for(int i=0;i<points.size();i++){
int curmax=1;
map<double,int>k_cnt;//斜率-直线上的点数目
int again=0;
int vnum=0;//考虑斜率便不能垂直,故单独计数
for(int j=0;j<points.size();j++)
{
if(j!=i){
int dx=points[i].x-points[j].x;
int dy=points[i].y-points[j].y;
if(dx==0&&dy==0)again++;//重合
else if(dx==0){if(vnum==0)vnum=2;else vnum++;curmax=max(curmax,vnum);}//垂直
else{
double k=(double)dy/(double)dx;
if(k_cnt[k]==0)k_cnt[k]=2;
else k_cnt[k]++;
curmax=max(curmax,k_cnt[k]);
}//存在斜率时候
}
}
res=max(res,curmax+again);
}
return res;
}
};
AC不了:
由于k的斜率是浮点数,存在存储精度问题,当k很大时趋于相同故这里选择存在dy/dx的最简分数形式,这样可以精确表示效率:
改进代码:
int gcd(int x,int y){
int z=y;
while(y!=0){
z=y;
y=x%y;
x=z;
}
return x;
}//两个数最大公约数
int maxPoints(vector<Point>& points){
if(points.empty())return 0;
if(points.size()==1)return 1;
int res=0;
for(int i=0;i<points.size();i++){
int curmax=1;
//map<double,int>k_cnt;//斜率-直线上的点数目
map<pair<int,int>,int>k_cnt;
int again=0;
int vnum=0;//考虑斜率便不能垂直,故单独计数
for(int j=0;j<points.size();j++)
{
if(j!=i){
int dx=points[i].x-points[j].x;
int dy=points[i].y-points[j].y;
if(dx==0&&dy==0)again++;//重合
else if(dx==0){if(vnum==0)vnum=2;else vnum++;curmax=max(curmax,vnum);}//垂直
else{
/*double k=(double)dy/(double)dx;
if(k_cnt[k]==0)k_cnt[k]=2;
else k_cnt[k]++;
curmax=max(curmax,k_cnt[k]);*/
int g=gcd(dx,dy);
dx/=g;dy/=g;
if(k_cnt[make_pair(dx,dy)]==0)k_cnt[make_pair(dx,dy)]=2;
else k_cnt[make_pair(dx,dy)]++;
curmax=max(curmax,k_cnt[make_pair(dx,dy)]);
}//存在斜率时候
}
}
res=max(res,curmax+again);
}
return res;
}