[LeetCode] 149.直线上最多的点数(Hard)C语言题解

题目

  • 给定一个二维平面,平面上有 n 个点,求最多有多少个点在同一条直线上。

示例

①示例1

在这里插入图片描述

②示例2

在这里插入图片描述


说明

①相关话题
  • 哈希表
  • 数学
②题目地址

解题方法

①暴力解法
  • 由于三点确定一条直线,我们可以选取所有可能的两个点,然后从剩余的点中判断是否和选取的两个点在同一条直线上。
  • 注意:不能用公式 ( l o n g i n t ) ( y 1 − y 2 ) / ( x 1 − x 2 ) = = ( l o n g i n t ) ( y 3 − y 2 ) / ( x 3 − x 2 ) (long int)(y1-y2) / (x1-x2) == (long int)(y3-y2) / (x3-x2) (longint)(y1y2)/(x1x2)==(longint)(y3y2)/(x3x2) 比较,这样可能会出现除以0的情况,需要转换成 ( l o n g i n t ) ( y 1 − y 2 ) ∗ ( x 3 − x 2 ) = ( l o n g i n t ) ( y 3 − y 2 ) ∗ ( x 1 − x 2 ) (long int)(y1-y2) * (x3-x2) = (long int)(y3-y2) * (x1-x2) (longint)(y1y2)(x3x2)=(longint)(y3y2)(x1x2)
  • 时间复杂度:O(N^3)。
  • 空间复杂度:O(1)。
②数学 + 哈希表
  • 因为键值不是整数,所以这里的哈希表使用 uthash
  • uthash 是一个用 C 语言编写的开源库,使用宏实现了哈希表的增删改查等功能。
  • 因为两点可以确定一条直线,且斜率相同的点在同一条直线上。所以我们可以选择每次固定一个点,求固定点与其他点的斜率,即哈希表的键值为此斜率,同时记录斜率相同的点的个数,每次通过哈希表找出其最大值,就可以得出与固定点有关的直线上的最多点数。
  • 而两点间的斜率值类型为浮点型,不能做 uthash 的键值,所以先要把浮点数转化为字符串,然后用字符串做键值。
  • 注意重复点、斜率不存在的点都要额外处理。
  • 时间复杂度:O(N^2)。
  • 空间复杂度:O(N)。

代码详解

  • 暴力解法
int maxPoints(struct Point* points, int pointsSize) {
    if (pointsSize < 3)
        return pointsSize;
    
    int max = 0;
    
    for (int i = 0; i < pointsSize; i++) {
        for (int j = i+1; j < pointsSize; j++) {
            int count = 2;
            
            for (int k = 0; k < pointsSize; k++) {
                if (k != i && k != j) {
                    int x1 = points[i].x, y1 = points[i].y, x2 = points[j].x, y2 = points[j].y, x3 = points[k].x, y3 = points[k].y;
                    
                    // 若x1等于x2,则x3必须在直线x = x1/x2上。
                    if (x1 == x2 && x3 == x1)
                        count++;
                    // 两点式(y-y2) = (y2-y1)*(x-x2)/(x2-x1)成立的条件是分母不为0。
                    else if (x1 != x2 && (long int)(y3-y2)*(x2-x1) == (long int)(y2-y1)*(x3-x2))
                        count++;    
                }                
            }    
            
            // 更新最大值。
            max = max > count? max: count;
        }
    }
    
    return max;
}  
  • 数学 + 哈希表(uthash)
int maxPoints(struct Point* points, int pointsSize) {
    struct hash {
        char key[30];
        int count;
        UT_hash_handle hh; 
    };
    
    int max = 0;
    
    for (int i = 0; i < pointsSize; i++) {
        struct hash *hashTable = NULL;
        int c1 = 0, c2 = 1;

        for (int j = 0; j < pointsSize; j++) {
            int m = points[i].x-points[j].x, n = points[i].y-points[j].y;
            
            if (j != i) {
                // 重复的点用c1记录,最后直接加给c2。
                if (points[i].x == points[j].x && points[i].y == points[j].y)
                    c1++;
                // 斜率存在时。
                else if (m != 0) {
                    struct hash *h;
                    double k = n == 0? 0.0: (double)m / n;
                    char s[30];
                    // 将斜率的计算结果保留到小数点后20位,并转为字符串。
                    sprintf(s, "%.20f", k);
                    HASH_FIND_STR(hashTable, s, h);
                
                    if (h)
                        h->count++;
                    else {
                        h = malloc(sizeof(struct hash));
                        strcpy(h->key, s);
                        // 记录斜率为该键值的直线上的点的个数(包括该点)。
                        h->count = 2;
                        HASH_ADD_STR(hashTable, key, h);
                    }
                }
                // 斜率不存在时(90°)。
                else
                    c2++;
            }
        }  
           
        // 此时c2的初值为斜率不存在的直线上的点的个数(包括该点)。
        if (hashTable) {
            // 逐一与其他直线上的点的个数作比较,找出最大值。
            for (struct hash *s = hashTable; s!= NULL; s = s->hh.next)
                c2 = s->count > c2? s->count: c2;
        }  
        
        // 更新最大值。
        max = c1+c2 > max? c1+c2: max;
    }
    
    return pointsSize == 0? 0: max;
}

附录

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值