1. 程式人生 > >[CareerCup] 7.6 The Line Passes the Most Number of Points 經過最多點的直線

[CareerCup] 7.6 The Line Passes the Most Number of Points 經過最多點的直線

7.6 Given a two-dimensional graph with points on it, find a line which passes the most number of points.

這道題給了我們許多點,讓我們求經過最多點的一條直線。給之前那道7.5 A Line Cut Two Squares in Half 平均分割兩個正方形的直線一樣,都需要自己寫出點類和直線類。在直線類中,我用我們用斜率和截距來表示直線,為了應對斜率不存在情況,我們還需用一個flag來標記是否為垂直的線。在直線類中,我們要有判斷兩條直線是否相等的函式。判斷相等的方法和之前那道7.3 Line Intersection 直線相交

相同,都需要使用epsilon,只要兩個數的差值的絕對值小於epsilon,我們就認定是相等的。對於給定的所有點,每兩個點能組成一條直線,我們的方法是遍歷所有的直線,把所有相同的直線都存入雜湊表中,key是直線的斜率,對映關係是斜率和直線集合的對映,那麼我們只需找到包含直線最多的那個集合即可,參見程式碼如下:

class Point {
public:
    double _x, _y;
    Point(double x, double y): _x(x), _y(y) {};
};

class Line {
public:
    static constexpr double
_epsilon = 0.0001; double _slope, _intercept; bool _infi_slope = false; Line(Point p, Point q) { if (fabs(p._x - q._x) > _epsilon) { _slope = (p._y - q._y) / (p._x - q._x); _intercept = p._y - _slope * p._x; } else { _infi_slope
= true; _intercept = p._x; } } static double floorToNearestEpsilon(double d) { int r = (int)(d / _epsilon); return ((double)r) * _epsilon; } bool isEquivalent(double a, double b) { return (fabs(a - b) < _epsilon); } bool isEquivalent(Line other) { if (isEquivalent(_slope, other._slope) && isEquivalent(_intercept, other._intercept) && (_infi_slope == other._infi_slope)) { return true; } return false; } }; class Solution { public: Line findBestLine(vector<Point> &points) { Line res(points[0], points[1]); int bestCnt = 0; unordered_map<double, vector<Line> > m; for (int i = 0; i < (int)points.size(); ++i) { for (int j = i + 1; j < (int)points.size(); ++j) { Line line(points[i], points[j]); insertLine(m, line); int cnt = countEquivalentLines(m, line); if (cnt > bestCnt) { res = line; bestCnt = cnt; } } } return res; } void insertLine(unordered_map<double, vector<Line> > &m, Line &line) { vector<Line> lines; double key = Line::floorToNearestEpsilon(line._slope); if (m.find(key) != m.end()) { lines = m[key]; } else { m[key] = lines; } lines.push_back(line); } int countEquivalentLines(unordered_map<double, vector<Line> > &m, Line &line) { double key = Line::floorToNearestEpsilon(line._slope); double eps = Line::_epsilon; return countEquivalentLines(m[key], line) + countEquivalentLines(m[key - eps], line) + countEquivalentLines(m[key + eps], line); } int countEquivalentLines(vector<Line> &lines, Line &line) { if (lines.empty()) return 0; int res = 0; for (auto &a : lines) { if (a.isEquivalent(line)) ++res; } return res; } };