zoukankan      html  css  js  c++  java
  • [LeetCode]Max Points on a Line

    题目:Max Points on a Line

    找到给定的点集中在一条直线上的最大点数。

    思路:

    两点确定一条直线,可以通过y=k*x+b中的k和b来确定直线;

    k=(y1-y0)/(x1-x0)  b=(x1*y0-x0*y1)/(x1-x0);

    所以用double类型存储k,b;

    遍历每个点找到k,b相同的直线。

    注意:

    可能有相同坐标的点和横坐标相同(k为无穷大)的点。

    int maxPoints(vector<Point>& points) {
            if (points.size() < 3)return points.size();
            int max = 2;
            double MAX_DOUBLE = 1.7E308;
            double MIN_DOUBLE = 1.0E-100;
            auto it = points.cbegin();
            while (it != points.cend()){
                //cur统计it的每个点的对应的直线上的最大点数量
                int cur = 1,equalCount = 0;//equalCount统计与it对应的点相同的点数量。
                auto p = it + 1;
                unordered_map<double,pair<double,int>>arr;
                while (p != points.cend()){
                    double a = (p->x - it->x);
                    double k = (p->y - it->y);
                    double b = 0.0;
                    if (a < MIN_DOUBLE && a > -MIN_DOUBLE){
                        if (k < MIN_DOUBLE && k > -MIN_DOUBLE){//两个点相同
                            ++equalCount;
                            ++p;
                            continue;
                        }
                        else{//横坐标相等
                            k = MAX_DOUBLE;
                            b = MAX_DOUBLE;
                        }
                    }
                    else{//其他情况
                        k = k / a;
                        b = (p->x*it->y - p->y*it->x)*1.0 / a;
                    }
                    auto pos = arr.find(k);
                    int count = 2;
                    if (pos == arr.cend())arr[k] = make_pair(b,2);//没有同一条直线的点
                    else if (pos->second.first - b > MIN_DOUBLE || pos->second.first - b < -MIN_DOUBLE){//k相同,b不同
                        arr[k] = make_pair(b, 2);
                    }
                    else{//在同一条直线上
                        count = ++(pos->second.second);
                    }
                    if (count > cur)cur = count;
                    ++p;
                }
                cur += equalCount;
                if (cur > max)max = cur;
                ++it;
            }
            return max;
        }

    但是上面的算法不能通过所有的测试用例,因为double的精度损失,导致无法区分不同的k值;

    所以考虑用int比较。

    a*y = k*x + b;其中a = x1 - x0;k = y1 - y0;b = x1*y0 - x0*y1;

    是不是一定需要这三个数呢?

    b = x1*y0 - x0*y1 = (x1 - x0)*y0 - (y1 - y0)*x0 = a*y0 - k*x0 = a*y1 - k*x1;

    由于循环比较的时候有一个点是固定不变的,所以上面的b也是固定的,它是否相等,完全取决于a和k;

    于是只需要比较两个元素a和k,但是a,k还需要除以他们的最大公因数,因此需要一个求最大公因数的函数;

    同时,也要考虑:坐标相同的点和横坐标相等的点。

    int LeetCode::maxComDivisor(int a, int b){
        if (b)return maxComDivisor(b,a%b);
        else return a;
    }
    
    int LeetCode::maxPoints(vector<Point>& points){
        if (points.size() < 3)return points.size();
        int max = 2;
        auto it = points.cbegin();
        while (it != points.cend()){
            //cur统计it的每个点的对应的直线上的最大点数量;equalCount统计与it对应的点相同的点数量,vertical统计垂直的线的个数。
            int cur = 1,equalCount = 0,vertical = 1;
            auto p = it + 1;
            map<pair<int,int>,int>arr;
            while (p != points.cend()){
                int a = p->x - it->x;
                int k = p->y - it->y;
                int b = p->x*it->y - p->y*it->x;
                if (!a){
                    if (!k){
                        ++equalCount;
                        ++p;
                        continue;
                    }
                    else{//横坐标相同的点
                        ++vertical;
                        if (vertical > cur)cur = vertical;
                    }
                }
                else{
                    int mcd = maxComDivisor(a, k);//求最大公约数
                    a = a / mcd;
                    k = k / mcd;
                    pair<int, int> temp(a, k); 
                    auto pos = arr.find(temp);
                    int count = 2;
                    //没有一条直线的点,则加入map
                    if (pos == arr.cend())arr[temp] = 2;
                    else{//有一条直线的点
                        count = ++(pos->second);
                    }
                    if (count > cur)cur = count;
                }
                ++p;
            }
            cur += equalCount;//加上与当前相同的点的数量
            if (cur > max)max = cur;
            ++it;
        }
        return max;
    }
  • 相关阅读:
    浏览器内核
    为什么一般请求可以下载文件,Ajax 请求就不能下载
    转 深入理解javascript原型和闭包(10)——this
    node读取文本文件时,去掉BOM
    AMD & CMD
    gulp requirejs Error: ENOENT: no such file or directory, open '/js/require_config.js', 一直报找不到require_config.js,坑死了
    [BZOJ3224]普通平衡树
    [NOIP2014D2]
    [NOIP2014D1]
    [NOIP2013D2]
  • 原文地址:https://www.cnblogs.com/yeqluofwupheng/p/6757820.html
Copyright © 2011-2022 走看看