【参考官方】
这道题太经典了,本科的时候就练习过,然而我还是忘了。
整体思路就是穷举法,不是很方便优化。穷举思路就是比照每两点之间的直线方程,但是考虑到所有的线都有基准点,那么只要比较斜率就可以了(平行线情形在有基准点的情况下不会影响结果)。
难点就是斜率的表示。【没错这里我还是不会,我是垃圾】
首先,给定两点 ( x 1 , y 1 ) (x_1, y_1) (x1,y1)和 ( x 2 , y 2 ) (x_2, y_2) (x2,y2),其斜率即 x 1 − x 2 y 1 − y 2 \frac{x_1 - x_2}{y_1 - y_2} y1−y2x1−x2,由于浮点数的保存形式,该结果不能保存成,只能用分数表示。
其次,不同的分数表示需要约分,因此需要使用最大公约数统一到质数形式。
再有,垂直线和水平线有一项为0,这个时候同一将另外一项处理成1。
最后,正负号问题,同一处理成y项为正。
此外还参考官方实现增加了几个剪枝:
class Solution {
public:
struct hash_pair{
size_t operator()(const pair<int, int> & p) const{
return p.second + p.first * 20001; // dy + dx * 20001
}
};
int maxPoints(vector<vector<int>>& points) {
int n = points.size();
if (n <= 2) {
return n;
}
int ans = 1;
for (int i = 0; i < n; i++) {
if (ans >= n - i || ans > n / 2) {
break;
}
unordered_map<pair<int, int>, int, hash_pair> lines;
for (int j = i + 1; j < n; j++) {
// 只考虑后面的点
int deltaX = points[i][0] - points[j][0];
int deltaY = points[i][1] - points[j][1];
if (deltaX == 0) {
deltaY = 1; // 水平线
} else if (deltaY == 0) {
deltaX = 1; // 垂直线
} else {
if (deltaY < 0) {
// 统一化正负号
deltaX = -deltaX;
deltaY = -deltaY;
}
// 最约化
int m = gcd(abs(deltaX), abs(deltaY));
deltaX /= m;
deltaY /= m;
}
lines[{deltaX, deltaY}]++;
}
int maxP = 0;
for (auto it = lines.begin(); it != lines.end(); ++it) {
maxP = max(maxP, it->second + 1);
}
ans = max(ans, maxP);
}
return ans;
}
private:
int gcd(int a, int b) {
return b ? gcd(b, a % b) : a;
}
};
Solution 1的Python实现
class Solution:
def maxPoints(self, points: List[List[int]]) -> int:
n = len(points)
if n <= 2: return n
ans = 1
for i in range(n):
if ans >= n - 1 or ans > n // 2: break
lines = collections.defaultdict(int)
for j in range(i + 1, n):
deltaX = points[i][0] - points[j][0]
deltaY = points[i][1] - points[j][1]
if deltaX == 0: deltaY = 1
elif deltaY == 0: deltaX = 1
else:
if deltaY < 0:
deltaX = -deltaX
deltaY = -deltaY
m = math.gcd(abs(deltaX), abs(deltaY))
deltaX /= m
deltaY /= m
lines[(deltaX, deltaY)] += 1
maxP = 0
for _, value in lines.items():
maxP = max(maxP, value + 1)
ans = max(ans, maxP)
return ans