Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.
主要思想:O(n2),固定一个点,遍历其余 n 个点, 计算与该点相同的点的个数,和其余所有点的斜率,相同斜率的点视为同一直线。
初步 AC 代码:
/** * 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) { unordered_map<float, int> mp; int maxNumber = 0; for(size_t i = 0; i < points.size(); ++i) { int repeat = 1; int sameX = 0; for(size_t j = 0; j < points.size(); ++j) { if(j == i) continue; if(points[j].x == points[i].x) { if(points[j].y == points[i].y) ++repeat; else ++sameX; } else { float k = (float)(points[i].y - points[j].y) / (points[i].x - points[j].x);// key. mp[k]++; } } unordered_map<float, int>::iterator it = mp.begin(); while(it != mp.end()) { if(it->second + repeat > maxNumber) maxNumber = it->second + repeat; ++it; } maxNumber = (repeat + sameX) > maxNumber ? (repeat + sameX) : maxNumber; mp.clear(); } return maxNumber; } };
但是里面的 hash map 使用了 浮点值做键值是个非常拙劣的方法。如下所述:
Testing equality with float ou double is always a bad idea because of rounding errors, so don't use them as a hash. Never. For it's floating point arithmetic, Java uses a subset of IEEE754. IEEE754 is full of beautiful tricks to mimic the behavior of real numbers and do a wonderful job at it, so sometimes we forget that is has limitations. The main troubles are (in no specific order): there is a gap between 0.0 and the next value (so non-zero numbers can be rounded to 0 if they are in this gap) there are special values for +infinity and -infinity (so there is no overflow, but you can get "stuck" on an infinite value. Imagine a*b evaluates to infinity, then a*b/bwill also evaluate to infinity and not to à`) there is a special value NaN that means not a number. (0.0 / 0.0 evaluates to NaN) there are signed zeroes (+0.0 and -0.0) Signed zeroes are usually not that painful (-0.0 == +0.0 for the primitive types double and float but not for their object wrappers Double and Float) To come back to your question, using Double as a key in the map is a terrible idea because of rounding problems. You do not need to use Math.PI for infinity since Double.POSITIVE_INFINITY is a legitimate value. Be careful though, you don't want to have positive and negative infinity mixed up. Look at the previous questions, the trick here is to represent a line by an equation ax+by+c=0 with a,b, and c of type int. As a final note, I think it is important to know the limitations of the encoding you are using (overflow for int, signed zeroes, infinity, and NaN of floating point numbers, surrogate pair for UTF-16…)
Testing equality with float ou double is always a bad idea because of rounding errors, so don't use them as a hash. Never.
For it's floating point arithmetic, Java uses a subset of IEEE754. IEEE754 is full of beautiful tricks to mimic the behavior of real numbers and do a wonderful job at it, so sometimes we forget that is has limitations. The main troubles are (in no specific order):
a*b
infinity
a*b/b
NaN
0.0 / 0.0
+0.0
-0.0
-0.0 == +0.0
double
float
Double
Float
To come back to your question, using Double as a key in the map is a terrible idea because of rounding problems. You do not need to use Math.PI for infinity since Double.POSITIVE_INFINITY is a legitimate value. Be careful though, you don't want to have positive and negative infinity mixed up. Look at the previous questions, the trick here is to represent a line by an equation ax+by+c=0 with a,b, and c of type int.
Math.PI
Double.POSITIVE_INFINITY
int
As a final note, I think it is important to know the limitations of the encoding you are using (overflow for int, signed zeroes, infinity, and NaN of floating point numbers, surrogate pair for UTF-16…)
所以待重新写答案 AC 一次。