一、Problem
给定一个二维平面及平面上的 N 个点列表Points,其中第i个点的坐标为Points[i]=[Xi,Yi]。请找出一条直线,其通过的点的数目最多。
设穿过最多点的直线所穿过的全部点编号从小到大排序的列表为S,你仅需返回[S[0],S[1]]作为答案,若有多条直线穿过了相同数量的点,则选择S[0]值较小的直线返回,S[0]相同则选择S[1]值较小的直线返回。
示例:
输入: [[0,0],[1,1],[1,0],[2,0]]
输出: [0,2]
解释: 所求直线穿过的3个点的编号为[0,2,3]
提示:
2 <= len(Points) <= 300
len(Points[i]) = 2
二、Solution
方法一:几何
思路
两个点 p o i n t i 、 p o i n t j point_i、point_j pointi、pointj 确定一条直线,用一般式 a x + b y + c = 0 ax+by+c=0 ax+by+c=0 作为判断公式统计在同一直线上的点的数量
a、b、c 怎么求?三个点可确定两条直线,又有直线的两点式:
x
−
x
1
x
2
−
x
1
=
y
−
y
1
y
2
−
y
1
\cfrac{x - x_1 }{x_2 - x_1} = \cfrac{y - y_1}{ y_2 - y_1}
x2−x1x−x1=y2−y1y−y1
两点式可转为直线的一般式:
a
x
+
b
x
+
c
=
0
ax + bx + c = 0
ax+bx+c=0
通分之后,代入系数解得 a、b、c:
a = y 2 − y 1 , b = x 1 − x 2 , 移 项 可 得 − c = a × x 1 + b × y 1 a = y_2 - y_1,b = x_1 - x_2,移项可得 -c = a × x_1 + b × y_1 a=y2−y1,b=x1−x2,移项可得−c=a×x1+b×y1
class Solution {
public:
bool isSameLine(vector<int>& p1, vector<int>& p2, vector<int>& p) {
int x=p[0], x1=p1[0], x2=p2[0], y=p[1], y1=p1[1], y2=p2[1];
long a=y2-y1, b=x1-x2, c=a*x1+b*y1;
return a*x+b*y-c==0;
}
vector<int> bestLine(vector<vector<int>>& ps) {
int n=ps.size(), mx=-1;
vector<int> ans(2);
for (int i=0; i<n-1; i++)
for (int j=i+1; j<n; j++) {
int same=0;
for (auto& p : ps) if (isSameLine(ps[i], ps[j], p))
same++;
if (same > mx) {
ans[0]=i, ans[1]=j, mx=same;
} else if (same == mx && i==ans[0] && j<ans[1]) {
ans[1]=j;
}
}
return ans;
}
};
1628 ms…
复杂度分析
- Time: O ( n 3 ) O(n^3) O(n3),
- Space: O ( 1 ) O(1) O(1)
可优化的地方是,利用斜率公式统计同一直线上点数量,可优化掉第三个循环,大致的思路是这样,处理一下重叠的点,写了有点久…
class Solution {
public:
int gcd(int a, int b) {
return a==0 ? b : gcd(b%a, a);
}
vector<int> bestLine(vector<vector<int>>& ps) {
int n=ps.size(), mx=-1;
vector<int> ans(2);
for (int i=0; i<n-1; i++) {
unordered_map<string, vector<int>> cnt;
int c=0, overlap=0;
for (int j=i+1; j<n; j++) {
int dx=ps[j][0]-ps[i][0], dy=ps[j][1]-ps[i][1], gcd_xy=(dx, dy);
if (dx==0 && dy==0) {
overlap++;
continue;
}
dx/=gcd_xy, dy/=gcd_xy;
string k=to_string(dx)+"#"+to_string(dy);
if (cnt.find(k) == cnt.end()) {
cnt[k] = {1, i, j};
} else {
cnt[k][0]++;
}
if (cnt[k][0] > mx) {
mx=cnt[k][0];
ans[0]=i, ans[1]=j;
} else if (cnt[k][0]==mx && i==ans[0] && j<ans[1]) {
ans[1]=j;
}
}
}
return ans;
}
};