题目描述
给定一个二维平面,平面上有 n 个点,求最多有多少个点在同一条直线上。
输入: [[1,1],[2,2],[3,3]]
输出: 3
解释:
^
|
| o
| o
| o
+------------->
0 1 2 3 4
解题思路
思路:固定一点,找其他点和这个点组成直线,,统计他们的斜率!
这里有一个重点: 求斜率,用两种方法:(题解,评论区有详细注释)
-
用最大约数方法(gcd),找到最大公约数后,把斜率化成最简形式,例
3/6 == 2/4 == 1/2-
辗转相除法, 又名“欧几里德算法”(Euclidean algorithm),是求最大公约数的一种方法。
gcd(a,b) = gcd(b, a mod b );,直到最后余数是0为止,此时的被除数就是这两个数的最大公约数。递归代码:
LL gcd(LL a,LL b){ return b==0? a: gcd(b, a % b); }
-
-
除数(不太精确, 速度快!)
详细注释版:(java)
class Solution {
public int maxPoints(int[][] points) {
int n = points.length;
if (n == 0)
return 0;
if (n == 1)
return 1;
int res = 0;
//对于第i个点只需考虑它和后面点的组合即可,因为和前面点的组合已经在更小的i时讨论过了
for (int i = 0; i < n - 1; i++) {
Map<String, Integer> slope = new HashMap<>();
//repeat记录和第i个点重复点的个数
int repeat = 0;
int tmp_max = 0;
for (int j = i + 1; j < n; j++) {
//dy为第j个点和第i个点之间y的距离
int dy = points[i][1] - points[j][1];
//dx为第j个点和第i个点之间x的距离
int dx = points[i][0] - points[j][0];
//dy=0=dx表明第j个点和第i个点重合了
if (dy == 0 && dx == 0) {
repeat++;
continue;
}
//求公约数,因为如果采用dy/dx的方式求斜率,如果是一条平行于y轴的线会造成除法错误
int g = gcd(dy, dx);
//这一步不仅是进行简单的约分
//对于特殊例子 [0,0]的两个点[1,-1]、[-1,1],两者公约数分别为-1、1,但除以公约数后为[-1,1]、[-1,1],变相同了(解决了1/2与-1/-2可能被划分为不同斜率的问题)
if (g != 0) { // 其实这个判断不用加,g不可能为0。
dy /= g;
dx /= g;
}
//String.valueOf(int)是将int数据类型直接转为stirng,eg:int为10则结果为"10",C++用to_string()
String tmp = String.valueOf(dy) + "/" + String.valueOf(dx);
//put为insert意思
//HashMap.getOrDefault(a,b)为如果在哈希表中找到key为a的则返回a的映射value,如果没找到a则返回b
//slope中更新斜率一样的点的个数
slope.put(tmp, slope.getOrDefault(tmp, 0) + 1);
tmp_max = Math.max(tmp_max, slope.get(tmp));
}
//重合的点也算在一条直线上,且重合的点可以说在任意一条直线上
res = Math.max(res, repeat + tmp_max + 1);
}
return res;
}
private int gcd(int dy, int dx) {
if (dx == 0) // 递归结束条件。
return dy;
else
return gcd(dx, dy % dx);
}
}
参考代码
C++
class Solution {
public:
int maxPoints(vector<vector<int>>& points) {
int numOfPoints = points.size();
if(numOfPoints <= 2) return numOfPoints;
int res = 0;
for(int i = 0; i < numOfPoints-1; i++){
int tmp_max = 0;
int repeat = 0;
unordered_map<string, int> umap;
for(int j = i+1; j < numOfPoints; j++){
int dx = points[j][0] - points[i][0];
int dy = points[j][1] - points[i][1];
if(dx == 0 && dy == 0){
repeat++;
continue;
}
int g = gcd(dy, dx);
if(g != 0){
dx /= g;
dy /= g;
}
string slope = to_string(dy) + "/" + to_string(dx);
umap[slope]++;
tmp_max = max(tmp_max, umap[slope]);
}
res = max(res, tmp_max + repeat + 1);
}
return res;
}
int gcd(int dy, int dx){
if(dx == 0)
return dy;
else
return gcd(dx, dy % dx);
}
};
本文探讨如何求解平面上n个点中最多有多少个点位于同一直线上。通过固定一个点,计算与其他点组成的直线斜率,并利用最大公约数进行斜率简化,避免浮点数误差,实现高效算法。
349

被折叠的 条评论
为什么被折叠?



