算法设计与分析第二周作业leetcode

题目原链接:
https://leetcode.com/problems/max-points-on-a-line/description/
Difficulty:Hard
Total Accepted:100.8K
Total Submissions:661.4K

题目需要求出在同一条直线的最大点数。
咋一看比较简单,于是就直接拿斜率来求解,斜率一样的也就是在一条直线上。
但很快开始暴露出问题,

  • 一是可能有不同的点位置重合
  • 二是斜率的精度应该要用何种方法存储,因为如果用浮点数存储,那么会有精度问题,特别是当点的横坐标和纵坐标比较大的时候,会出现精度误差,从而影响运算结果。
  • 第三点需要考虑的是数据存储结构,例如我一开始用struct+vector的方式存储,但在查找相同斜率的点时需要o(n)的复杂度,明显不如map的直接映射效率高。
//原来的数据结构
struct Slope {
    float slope;
    int times;
    Slope(float s,int t) :slope(s), times(t) {}
};

因此针对上面的三点,分别作出的该进如下:

  • 将重合的点用map< pair< int, int>, int> pointsMap来去重
  • 对于斜率精度问题,用string来存储被除数和除数,在存储之前先同时除以最大公约数化简。
  • 对于数据存储结构,利用map < string, int > 的结构代替struct slope+ vector < slope >
//原来的代码
class Solution {
    struct Slope {
        float slope;
        int times;
        Slope(float s,int t) :slope(s), times(t) {}
    };
    float slopeTemp;
    vector<Slope> SlopeVec;
    int samepoint;
    bool isPush;
    public:
        int maxPoints(vector<Point>& points) {//还有[] 的输入
            Slope ss(LONG_MAX,0);//用来存储横坐标相等的
            SlopeVec.push_back(ss);
            if (points.size() == 0) {
                return 0;
            }
            for (int i = 0; i < points.size(); i++) {
                samepoint = 0;
                for (int j = i+1; j < points.size(); j++) {
                    isPush = false;
                    if (points[i].x == points[j].x &&points[i].y == points[j].y) {
                        samepoint++;
                    }
                    else if (points[i].x == points[j].x) {
                        SlopeVec[0].times++;
                        break;
                    }
                    slopeTemp = (float)(points[i].y - points[j].y) / (float)(points[i].x - points[j].x);
                    for (int x = 1; x < SlopeVec.size(); x++) {//第零位用来存横坐标相等的
                        if ( fabs(slopeTemp-SlopeVec[x].slope)<1e-6 ) {
                            SlopeVec[x].times++;
                            isPush = true;
                        }
                    }
                    if (!isPush) {
                        Slope slope(slopeTemp, 1);
                        SlopeVec.push_back(slope);
                    }       
                }
            }
            int maxTimes = 0;
            for (int i = 0; i < SlopeVec.size(); i++) {
                if (SlopeVec[i].times > maxTimes) {
                    maxTimes = SlopeVec[i].times;
                }
            }
            int result = 1;
            while (maxTimes  != 1) {
                maxTimes = maxTimes - result;
                result++;
            }
            return result;
        }
};

下面是最终的通过代码,但效率还不够高,但理解较方便,先用map去重,再用记录斜率的map来存储同个斜率上的点数。

class Solution {
    map<pair<int, int>, int> pointsMap;
    int samepoint;
    int sameX;
    int result, resultTemp;
    int xLength, yLength, g;
public:
    /* 迭代法(递推法):欧几里得算法,计算最大公约数 */
    int gcd(int m, int n) {
        while (m>0) {
            int c = n % m;
            n = m;
            m = c;
        }
        return n;
    }
    int maxPoints(vector<Point>& points) {//还有[] 的输入
        result = 0;
        if (points.size() == 0) {
            return 0;
        }
        for (int i = 0; i < points.size(); i++) {
            pair<int, int> pairTemp(points[i].x, points[i].y);
            pointsMap[pairTemp]++;
        }
        for (auto i = pointsMap.begin(); i != pointsMap.end(); i++) {
            sameX = 0;
            resultTemp = 0;
            map<string, int> slopeMap;
            for (auto j = i; j != pointsMap.end(); j++) {
                if (i == j) {
                    continue;
                }
                if (i->first.first == j->first.first) {//points[i].x == points[j].x
                    pair<int, int> temp(j->first.first, j->first.second);
                    sameX += pointsMap[temp];
                }
                else {
                    xLength = i->first.first - j->first.first;
                    yLength = i->first.second - j->first.second;//points[i].y - points[j].y;    
                    g = gcd(abs(xLength), abs(yLength));//第一个系数不能为0
                    xLength /= g;
                    yLength /= g;
                    if (yLength < 0) {//确保y长度为正数
                        yLength *= -1;
                        xLength *= -1;
                    }
                    stringstream ss;
                    ss << xLength << "," << yLength;
                    string slopeStr(ss.str());
                    pair<int, int> temp(j->first.first, j->first.second);
                    slopeMap[slopeStr] += pointsMap[temp];
                    resultTemp = max(resultTemp, slopeMap[slopeStr]);//找到相同斜率下最多点的那个斜率
                }
            }
            resultTemp = max(resultTemp, sameX);//找出与此点同列的点数比较
            pair<int, int> temp(i->first.first, i->first.second);
            result = max(result, resultTemp + pointsMap[temp]);
        }
        return result;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值