LeetCode Max Points on a Line

平面上的点,求共线的最大点数。

Naive解法,对每两个点确定的直线,计算与这条直线共线的点数。未做优化,147ms。

/**
 * Definition for a point.
 * struct Point {
 *     int x;
 *     int y;
 * }
 */
 
// (在float的==比较中,隐含Nan != any not Nan,0.0 == -0.0,尤其注意!!)
#define Slope(i, j) (((double)(j.y) - i.y) / (j.x - i.x))
 
int maxPoints(struct Point* points, int pointsSize) {
    int i, j, k, res = 2;
    if (pointsSize <= 2)    // 少于3个点,返回点数。
        return pointsSize;
    for (i = 0 ; i < pointsSize ; i++)
        for (j = 0 ; j < pointsSize ; j++) {
            if (i == j) continue;
            int p = 2; // 至少有两个点共线了
            for (k = 0 ; k < pointsSize ; k++) {
                if (k == i || k == j)   continue;  // 三点不同
                if (points[i].x == points[k].x && points[i].y == points[k].y)
                    p++; // 重合点
                else if (points[j].x == points[k].x && points[j].y == points[k].y)
                    p++; // 重合点
                else if (points[i].x == points[j].x && points[j].x == points[k].x)
                    p++; // 斜率均不存在时
                else if (Slope(points[i], points[j]) == Slope(points[j], points[k]))
                    p++; // 否则,其中斜率之一存在,判断斜率是否相等。(在float的==比较中,隐含Nan != any not Nan,0.0 == -0.0,尤其注意!!)
            }
            if (p > res)
                res = p;
        }
    return res;
}

可以用hash对其进行优化(4ms过)。思想是,对每一个点,计算其它节点与他的斜率,放入一个hashtable并计数,最终取hashtalbe中累计最多的一个。

注意计算斜率的宏Slope,当两点斜率为无穷大时,我们设斜率为float的最大值,保证了逻辑上的Inf != any other && Inf == Inf,注意这里的等号和不等号是针对与二进制的物理表示的,因为我们在hashtable中,key的相等是依据直接比较二进制物理表示。

当两点斜率是0时,我们手动赋值0.0,否则可能出现-0.0物理内存不等于0.0的情况,从而在hashtable中认为是不同的key。

也就是说,naive中key的比较用的是C语言中的==和!=,所以不用关心物理表示;但在我们写的hashtable中,key的相同依据物理内存,因此需要我们对Slope做额外的确保。

#define Slope(i, j) (j.x == i.x ? 4294967295.0f : \
                    j.y == i.y ? 0.0f : ((float)(j.y-i.y)) / (j.x-i.x))

struct Mystruct {
    float slope;
    int num;
    struct B_HashHandle hh;
};
 
int maxPoints(struct Point* points, int pointsSize) {
    int i, j, k, res = 0;
    if (pointsSize <= 2)  // 少于3个节点返回点数
        return pointsSize;
    struct Mystruct* mystruct = malloc(sizeof(struct Mystruct) * pointsSize); // 最多hashtable中可能插入点数相同个元素
    struct B_HashTable* ht = hashInit(struct Mystruct);
    for (i = 0 ; i < pointsSize ; i++) {
        hashClear(ht);
        int t = 0, cnt = 0; // cnt累计了重合点个数
        for (j = i+1 ; j < pointsSize ; j++) { // j从i+1开始,必须保证0.0 == -0.0的判断(在这里WA了,用GDB调了半天)
            if (points[i].x == points[j].x && points[i].y == points[j].y)
                cnt++;
            else {
                mystruct[t].slope = Slope(points[i], points[j]);
                struct Mystruct* ret = hashSafeInsertField(ht, mystruct[t], slope);
                if (ret)
                    ret->num++;
                else {
                    mystruct[t].num = 1;
                    t++;
                }
            }
        }
        if (cnt > res) // 若没有此举,考虑这样的例子:三点重合,则以下循环不会发生,res不会更新为cnt
            res = cnt;
        struct Mystruct* iter = hashIter(ht);
        for ( ; iter ; iter = hashIterNext(ht, iter))
            if (cnt + iter->num > res)
                res = cnt + iter->num;
    }
    hashDestroy(ht);
    free(mystruct);
    return res + 1; // 最后要算上自己(我们的工作是,对每一个点,计算其它节点与他的斜率,放入一个hashtable并计数,最终还需累计他自己共线)
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值