题目:
Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.
题目来源:https://oj.leetcode.com/problems/max-points-on-a-line/
解题思路:由两点计算出斜率,然后根据斜率和初始点计算任意一点是否在这两点所确定的直线上,如果在就把计数器+1,返回最多的点的直线上的点数。
注意:如果第一个点是[1,3],第5个点也是[1,3],则在第5个点往后的点,以[1,3]为起点计算时,都需要加两遍[1,3],这个地方要特别注意。但是leetcode题解上避免了这个问题,可以从代码上看出来,如果点M和点N的x轴坐标相等,则只计算和x轴其坐标相等的点,否则利用公式计算。这样就把两个相等的点放到了第一种情况。
#include<iostream>
#include<vector>
using namespace std;
struct Point
{
int x;
int y;
Point() : x(0), y(0) {}
Point(int a, int b) : x(a), y(b) {}
};
int maxPoints(vector<Point> &points)
{
if(points.size()<=1)
return points.size();
const int N=points.size();
int result=0,temp=1;
for(int i=0;i<N;i++)
{
temp=1;
int firstNum=temp;
for(int j=i+1;j<N;j++)
{
if(points[j].x==points[i].x && points[j].y==points[i].y)
{
temp++;
//表示到目前为止第一个数即points[i]重复出现的次数,因为每次重复相当于每条线都有加一个点
firstNum++;
continue;
}
temp++;
double k=(points[j].x-points[i].x)==0?0:double(points[j].y-points[i].y)/(points[j].x-points[i].x);
for(int m=j+1;m<N;m++)
{
double tempk=(points[m].x-points[i].x)==0?0:double(points[m].y-points[i].y)/(points[m].x-points[i].x);
if(k==tempk || (points[m].x==points[i].x && points[m].y==points[i].y) || (points[m].x==points[j].x && points[m].y==points[j].y))
temp++;
}
if(temp>result)
result=temp;
temp=firstNum;
}
if(temp>result)
result=temp;
}
return result;
}
int maxPoints1(vector<Point> &points)
{
if(points.empty())
return 0;
const int N=points.size();
int temp=0;
int result=0;
for(int i=0;i<N;i++)
{
temp=1;
int firstNum=temp;
for(int j=i+1;j<N;j++)
{
int A=points[i].x-points[j].x;
int B=points[i].y-points[j].y;
if(A==0 && B==0)
{
temp++;
firstNum++;
continue;
}
temp++;
for(int m=j+1;m<N;m++)
{
if((A==0 && points[m].x==points[i].x) || (points[m].y-points[i].y)*A==B*(points[m].x-points[i].x))
temp++;
}
result=max(result,temp);
temp=firstNum;
}
result=max(result,temp);
}
return result;
}
int maxPoints2(vector<Point> &points)
{
if(points.size()<3)
return points.size();
int result=0;
for(int i=0;i<points.size()-1;i++)
{
for(int j=i+1;j<points.size();j++)
{
int sign=0;
int a,b,c;
if(points[i].x==points[j].x)
sign=1;
else
{
a=points[j].x-points[i].x;
b=points[j].y-points[i].y;
c=a*points[i].y-b*points[i].x;
}
int count=0;
for(int k=0;k<points.size();k++)
{
//这里巧妙的避免了上面所出现的问题及firstNum的问题
if((0==sign && a*points[k].y==c+b*points[k].x) || (1==sign && points[k].x==points[j].x))
count++;
}
if(count>result)
result=count;
}
}
return result;
}
int main()
{
freopen("input.txt","r",stdin);
vector<Point> points;
int x,y;
while(cin>>x>>y)
{
points.push_back(Point(x,y));
}
int result=maxPoints(points);
int result1=maxPoints1(points);
int result2=maxPoints2(points);
system("pause");
return 0;
}
以上的跌代版的时间复杂度是O(n^3),下面的算法是以每个点为中心,计算构成的每条线的斜率来算的,这样能够使复杂度降低到O(n^2),参考的是《leetcode题解》。
#include<iostream>
#include<vector>
#include<unordered_map>
using namespace std;
struct Point
{
int x;
int y;
Point() : x(0), y(0) {}
Point(int a, int b) : x(a), y(b) {}
};
int maxPoints(vector<Point> &points)
{
if(points.size()<3)
return points.size();
const int N=points.size();
int result=0;
unordered_map<double,int> slopmap;
for(int i=0;i<N;i++)
{
slopmap.clear();
int samePoint=0;
int commenLineNum=1;
for(int j=i+1;j<N;j++)
{
double slop;
if(points[i].x==points[j].x && points[i].y==points[j].y)
{
samePoint++;
continue;
}
if(points[i].x==points[j].x)
slop=double(INT_MAX);
else
slop=double(points[i].y-points[j].y)/(points[i].x-points[j].x);
int count=0;
if(slopmap.find(slop)!=slopmap.end())
count=++slopmap[slop];
else
{
count=2;
slopmap[slop]=count;
}
if(count>commenLineNum)
commenLineNum=count;
}
result=max(result,samePoint+commenLineNum);
}
return result;
}
int main()
{
freopen("input.txt","r",stdin);
vector<Point> points;
int x,y;
while(cin>>x>>y)
{
points.push_back(Point(x,y));
}
int result=maxPoints(points);
system("pause");
return 0;
}