程序员面试金典 16.14

Best Line:给定平面上n个点,找出一条直线,使其通过的点数最多。

书上的解法:求出两两相连后的斜率,平行线归为一类,在平行线中找重合的直线。由于存在浮点数误差,斜率差值小于epsilon的也算做平行线。

由于力扣上的输入都是整数,所以不用考虑epslion的问题。要求返回序号最小的两个点,所以对于同一斜率的平行线,只统计在它后面被添加的平行线上的点就可以了,但是要注意判重。根据这两点调整了一下书上的写法,不过超时了。

class Solution {
    int nPoint;
    static bool equal(const double d1, const double d2)
    {
        return abs(d1 - d2) <= 1e-6;
    }
    struct Line
    {
        double slope, intercept;
        bool bVertical;
        int i, j;
        Line(const vector<int> &p1, const vector<int> &p2, const int idx1, const int idx2) : i(idx1), j(idx2)
        {
            if(Solution::equal((double)p1[0], (double)p2[0])){
                bVertical = true;
                slope = 0.0;
                intercept = p1[0];
            }
            else{
                bVertical = false;
                slope = 1.0 * (p1[1] - p2[1]) / (p1[0] - p2[0]);
                intercept = p1[1] - slope * p1[0];
            }
        }
    };
    int countSameSlope(const size_t k, const vector<Line> &lines)
    {
        int cnt = 2;
        vector<bool> vbPoint(nPoint, false);
        vbPoint[lines[k].i] = true, vbPoint[lines[k].j] = true;
        for(size_t i = k + 1; i < lines.size(); i++)
        {
            if((lines[k].bVertical && lines[i].bVertical && Solution::equal(lines[k].intercept, lines[i].intercept)) ||
                (Solution::equal(lines[k].slope, lines[i].slope) && Solution::equal(lines[k].intercept, lines[i].intercept))){
                cnt += (vbPoint[lines[i].i] ? 0 : 1) + (vbPoint[lines[i].j] ? 0 : 1);
                vbPoint[lines[i].i] = true, vbPoint[lines[i].j] = true;
            }
        }
        return cnt;
    }
public:
    vector<int> bestLine(vector<vector<int>>& points) {
        nPoint = points.size();
        map<double, vector<Line>> mSlope2Line;
        vector<Line> VertLine;
        vector<int> S(2, nPoint);
        int maxCnt = 0;
        for(size_t i = 0; i < points.size(); i++)
        {
            for(size_t j = i + 1; j < points.size(); j++)
            {
                Line line(points[i], points[j], i, j);
                if(!line.bVertical){
                    mSlope2Line[line.slope].push_back(line);
                }
                else{
                    VertLine.push_back(line);
                }
            }
        }
        for(auto iter = mSlope2Line.begin(); iter != mSlope2Line.end(); iter++)
        {
            const vector<Line> &lines = iter->second;
            for(size_t k = 0; k < lines.size(); k++)
            {
                vector<int> s({lines[k].i, lines[k].j});
                int cnt = countSameSlope(k, lines);
                if(cnt > maxCnt){
                    maxCnt = cnt;
                    S = s;
                }
            }
        }
        for(size_t k = 0; k < VertLine.size(); k++)
        {
            vector<int> s({VertLine[k].i, VertLine[k].j});
            int cnt = countSameSlope(k, VertLine);
            if(cnt > maxCnt){
                maxCnt = cnt;
                S = s;
            }
        }
        return S;
    }
};

超时的原因可能是执行了两次循环,看起来时间复杂度在同一量级应该不影响,但是执行两次,时间还是会多一倍,如果把两个循环合并为一个,或许可以减少点时间。所以直接枚举所有可能的直线,再逐个判定序号更大的点是否在直线上即可。

class Solution {
    static bool equal(const double d1, const double d2)
    {
        return abs(d1 - d2) <= 1e-6;
    }
    struct Line
    {
        double slope, intercept;
        bool bVertical;
        Line(const vector<int> &p1, const vector<int> &p2)
        {
            if(Solution::equal((double)p1[0], (double)p2[0])){
                bVertical = true;
                slope = 0.0;
                intercept = p1[0];
            }
            else{
                bVertical = false;
                slope = 1.0 * (p1[1] - p2[1]) / (p1[0] - p2[0]);
                intercept = p1[1] - slope * p1[0];
            }
        }
    };
public:
    vector<int> bestLine(vector<vector<int>>& points) {
        int maxCnt = 0;
        int l1 = 0, l2 = 1;
        for(size_t i = 0; i < points.size(); i++)
        {
            for(size_t j = i + 1; j < points.size(); j++)
            {
                int cnt = 2;
                Line line(points[i], points[j]);
                for(size_t k = j + 1; k < points.size(); k++)
                {
                    if(!line.bVertical){
                        if(Solution::equal(line.slope * points[k][0] + line.intercept, (double)points[k][1])){
                            cnt++;
                        }
                    }
                    else{
                        if(Solution::equal(line.intercept, (double)points[k][0])){
                            cnt++;
                        }
                    }
                }
                if(cnt > maxCnt){
                    maxCnt = cnt;
                    l1 = i, l2 = j;
                }
            }
        }
        return vector<int>{l1, l2};
    }
};

你可能感兴趣的:(《程序员面试金典》)