题目如下:
Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.
思考分析:
一开始,我觉得这道题不是考算法的,题目确实不涉及算法的内容。但是后来,我交了很久才成功,才明白这道题的坑点在于corner cases.
首先,看解题方法。
假设在全部的n个点种,选定某一个点i,然后计算从i点到剩下的n-1个其它点构成的直线的斜率,如果[i, j1], [i, j2], [i, j3]斜率相同,显然i, j1, j2, j3就位于同一条直线上。用一
个map 来统计,斜率相同的点j1, j2, j3有多少个
但是其实点i不是固定的一点,它可以是n个点种的任何一个。所以在上面的循环外,再写一个循环。
基本思路如上。很直观。
然后,看坑点。
坑点1 如果直线是和y轴平行的,那么不能直接用(y1-y2)/(x1-x2)表示斜率,可以用INT_MAX表示斜率。
坑点2 如果有重复的点,如何处理。如[1,1], [2,2], [1,1],这是这道题目最关键的一点的,需要想清楚。对于选定的点i,在接下来计算定点i到剩下的n-1个点构成的斜率的时候,如果出现某点k和点i是相同的点,那么可以知道,点k将和任意一条和i共线的线共线,也就是说,需要单独用一个变量same_point_num来计数,看看和i相同的点有多少个,最后 在map中求了最多共线点后再加上same_point_num
坑点3 如何表示斜率相同的一堆点。注意点的坐标是int,斜率为了精确,需要设定为float或者double,这里涉及到精度转换的问题。
我的代码:
//104ms过大集合
/**
* 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.size()==0)
return 0;
int max_num=0;
int same_point_num=0;
for(int i=0;i<(int)points.size();i++){
map<double,int> slope_map;
same_point_num=0;
for(int j=0;j<(int)points.size();j++){
if(j==i) // i和i自己不需要计算
continue;
if(points[i].x-points[j].x==0&&points[i].y-points[j].y==0) //相同点
same_point_num++;
else if(points[i].x-points[j].x==0&&points[i].y-points[j].y!=0) //斜率为tan90°的点
slope_map[INT_MAX]++;
else
slope_map[double(points[j].y-points[i].y)/(points[j].x-points[i].x)]++; //正常点,注意double写的位置
}
int tmp_max=0;
for(map<double,int>::iterator it=slope_map.begin();it!=slope_map.end();it++){ //找到map中含有最多的点的斜率
if(it->second>tmp_max)
tmp_max=it->second;
}
if(tmp_max+same_point_num>max_num) //用map中的最多点再加上same_point_num得到的数和历史的最大值做比较跟新历史最大值
max_num=tmp_max+same_point_num;
}
return max_num+1;//当max_num为1时,确定了1条直线,2个点;当max_num为2时,确定了3个点;当max_num为i时,确定了i+1个点。
}
};
小结扩展:
(1) int a, int b
double c1=(double)(a/b);
double c2=(double)a/b;
一个需要注意细节的问题。上面的表达式中,c1返回的是int提升为double后的值,如5/2,返回的是2.0,这不是本题想要的结果。 c2返回的是5/2=5.0/2=2.5,是本题想要的结果。要注意这种细节方面的问题。