《LeetCode之每日一题》:69.直线上最多的点数

直线上最多的点数


题目链接: 直线上最多的点数

有关题目

给你一个数组 points ,其中 points[i] = [xi, yi] 表示 X-Y 平面上的一个点。
求最多有多少个点在同一条直线上。

在这里插入图片描述
在这里插入图片描述

提示:

1 <= points.length <= 300
points[i].length == 2
-10^4 <= xi, yi <= 10^4
points 中的所有点 互不相同

题解

法一:哈希表

思路:
统计其他所有点与点 i 所连直线的斜率
出现次数最多的斜率即为经过点数最多的直线的斜率,存放在ret中
struct HashTable
    {
        int key,val;
        UT_hash_handle hh;
    };

    //递归实现求解最大公约数,去除1 / 2 = 2 / 4斜率重合现象
    int gcd(int a,int b)
    {
        return b ? gcd (b, a % b) : a;
    }
int maxPoints(int** points, int pointsSize, int* pointsColSize){
   int n = pointsSize;
   //特判
   if (n <= 2)
        return n;
    int ret = 0;//存放最大值
    for (int i = 0; i < n; i++)
    {
        //①
        //对点i来说,至多只能找到n - i个点共线,若满足之前找到的ret >= n - i,则最大值肯定
        //无法出现i之后的点中了,直接拿到答案
        //②
        //当我们找到一条直线经过了图中超过半数的点时,我们即可以确定该直线即为经过最多点的直线
        //直接拿到答案


//为什么 ret > n /2就直接返回 ret 了。假设我五个点在一条线上此时枚举了三个点 ret =3> n /2岂不是直接返回3
//解:第二层 for 循环已经把斜率一样的点加进 map 集合中了,你可以参考案例[[1,1],[2,2],[3,3]],在 points [ i ][0] - points [ j ][0]这里已经实现后续的遍历
        if (ret >= n - i || ret > n / 2)
            return ret;
        struct HashTable* hashtable = NULL;
        for (int j = i + 1; j < n; j++)
        {
            //浮点数类型可能因为精度不够而无法足够精确地表示每一个斜率
            //因此我们将斜率 = (y增量) / (x增量)用分子和分母组成的二元组来代表斜率,即(my,mx)
            int x = points[i][0] - points[j][0];//x增量
            int y = points[i][1] - points[j][1];//y增量
            //我们对于x和y为零时的特殊情况进行特判
            //同时我们保证y增量为正,若遇到斜率为负的情况,我们对二元组中两个数同时取相反数
            if (x == 0)
                y = 1;
            else if (y == 0)
                x = 1;
            else
            {
                if (y < 0)
                {
                    x = -x;
                    y = -y;
                }
             int gcdXY = gcd(abs(x),abs(y));
             x /= gcdXY, y /= gcdXY;
            }
            //创建哈希表存放,斜率和对应出现次数
            struct HashTable* tmp;
            //结合横纵坐标的范围-10^4 <= xi, yi <= 10^4
            //我们利用构造一个法则val = y + 20001 * x通过一个整形int来表示x和y这两个整数即用来表示斜率
            int val = y + 20001 * x;
            HASH_FIND_INT(hashtable,&val,tmp);
            if (tmp == NULL)
            {
                tmp = (struct HashTable*)malloc(sizeof(struct HashTable));
                tmp->key = val;//上方的创建法则表示的斜率值
                tmp->val = 1;//对于斜率出现一次
                HASH_ADD_INT(hashtable,key,tmp);
            }
            else
                tmp->val++;
        }
        //找出哈希表中的对应斜率key出现最多的次数val
        int maxn = 0;
        struct HashTable *iter, *tmp;
        HASH_ITER(hh,hashtable,iter,tmp){
            maxn = fmax(maxn,iter->val + 1);
            HASH_DEL(hashtable,iter);
            free(iter);
        }
        ret = fmax(maxn,ret);
    }
    return ret;
}

C++

class Solution {
public:
  //递归实现求解最大公约数,去除1 / 2 = 2 / 4斜率重合现象
    int gcd(int a,int b)
    {
        return b ? gcd (b, a % b) : a;
    }
    int maxPoints(vector<vector<int>>& points) {
        int n = points.size();
        //特判
        if (n <= 2)
            return n;
        int ret = 0;//存放最大值
        for (int i = 0; i < n; i++)
        {
            if (ret >= n - i || ret > n / 2)
                return ret;
            unordered_map<int,int> mp;
            for (int j = i + 1; j < n; j++)
            {
                int x = points[i][0] - points[j][0];//x增量
                int y = points[i][1] - points[j][1];//y增量
                if (x == 0)
                    y = 1;
                else if (y == 0)
                    x = 1;
                else 
                {
                    if (y < 0)
                    {
                        x = -x;
                        y = -y;
                    }
                    int gcdXY = gcd(abs(x),abs(y));
                    x /= gcdXY, y /= gcdXY;
                }
                mp[y + 20001 * x]++;                
            }
            int maxn = 0;
            for (auto& [_,num] : mp)
                {
                    maxn = max(maxn,num + 1);    
                }
             ret = max(ret,maxn);            
        }
       return ret;
    }
    
};

在这里插入图片描述

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值