进阶之路

首页 新随笔 管理

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 一次。

 

 

 

posted on 2014-08-10 00:38  进阶之路  阅读(186)  评论(0编辑  收藏  举报