您的位置:首页 > 其它

LeetCode Max Points on a Line

2015-05-16 10:16 316 查看
平面上的点,求共线的最大点数。

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并计数,最终还需累计他自己共线)
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  LeetCode