首页 > 代码库 > Max Points on a Line

Max Points on a Line

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…)

 所以待重新写答案 AC 一次。