文章目录
- 写在前面
- Tag
- 题目来源
- 解题思路
- 方法一:枚举直线+遍历统计
- 方法二:枚举斜率+哈希统计
- 写在最后
写在前面
本专栏专注于分析与讲解【面试经典150】算法,两到三天更新一篇文章,欢迎催更……
专栏内容以分析题目为主,并附带一些对于本题涉及到的数据结构等内容进行回顾与总结,文章结构大致如下,部分内容会有增删:
- Tag:介绍本题牵涉到的知识点、数据结构;
- 题目来源:贴上题目的链接,方便大家查找题目并完成练习;
- 题目解读:复述题目(确保自己真的理解题目意思),并强调一些题目重点信息;
- 解题思路:介绍一些解题思路,每种解题思路包括思路讲解、实现代码以及复杂度分析;
- 知识回忆:针对今天介绍的题目中的重点内容、数据结构进行回顾总结。
Tag
【数学-点在线上】
题目来源
149. 直线上最多的点数
解题思路
方法一:枚举直线+遍历统计
我们都知道两点确定一条直线,为了统计最多有多少个点可以落在同一条直线上,我们可以枚举所有的直线,然后统计剩余落在该直线上的点的个数,最后取出不同直线上的点数的最大值即为最终答案。
为了判断点 p
是否落在点 x
和 y
确定的直线上,我们通过三点的任意两点之间的斜率是否相同来确定。
比如可以判断点 x
和 y
的斜率与 y
和 p
之间的斜率是否一致,即判断
y [ 1 ] − x [ 1 ] y [ 0 ] − x [ 0 ] = y [ 1 ] − p [ 1 ] y [ 0 ] − p [ 0 ] \frac{y[1] - x[1]}{y[0] - x[0]} = \frac{y[1] - p[1]}{y[0] - p[0]} y[0]−x[0]y[1]−x[1]=y[0]−p[0]y[1]−p[1]
是否成立。但是除法运算容易引发精度误差,为了防止这一问题对结果的影响,我们可以将上式转换成乘法表达式,直接判断:
( y [ 1 ] − p [ 1 ] ) ∗ ( y [ 0 ] − x [ 0 ] ) = ( y [ 1 ] − x [ 1 ] ) ∗ ( y [ 0 ] − p [ 0 ] ) (y[1] - p[1]) * (y[0] - x[0]) = (y[1] - x[1]) * (y[0] - p[0]) (y[1]−p[1])∗(y[0]−x[0])=(y[1]−x[1])∗(y[0]−p[0])
是否成立。
实现代码
class Solution {
public:int maxPoints(vector<vector<int>>& points) {int res = 0, n = points.size();if (n == 1) return 1;for (int i = 0; i < n-1; ++i) { // x 点for (int j = i + 1; j < n; ++j) { // y 点int cnt = 0; for (int k = 0; k < n; ++k) { // p 点if ((points[j][1] - points[k][1]) * (points[j][0] - points[i][0]) == (points[j][1] - points[i][1]) * (points[j][0] - points[k][0])) {++cnt;}}res = max(res, cnt);}}return res;}
};
复杂度分析
时间复杂度: O ( n 3 ) O(n^3) O(n3)。
空间复杂度: O ( 1 ) O(1) O(1)。
方法二:枚举斜率+哈希统计
方法二参考 枚举直线 + 哈希表统计。
在方法一中枚举的是直线,其实本质上枚举的是斜率,接着判断其它点与该直线的一点连接的直线斜率是否一致。
现在,我们可以直接枚举所有出现的 直线斜率,使用哈希表统计所有斜率对应的点的数量,在所有值中去个最大值即为答案。
注意:在使用哈希表进行保存时,为了避免精度问题,我们直接使用字符串进行保存。同时需要将 斜率 约分干净再记录到哈希表中。
实现代码
class Solution {
public:int maxPoints(vector<vector<int>>& points) {int n = points.size(), res = 1;for (int i = 0; i < n; i++) {map<string, int> map;int maxv = 0;for (int j = i + 1; j < n; j++) {int x1 = points[i][0], y1 = points[i][1], x2 = points[j][0], y2 = points[j][1];int a = x1 - x2, b = y1 - y2;int k = gcd(a, b);string key = to_string(a / k) + "_" + to_string(b / k);map[key]++;maxv = max(maxv, map[key]);}res = max(res, maxv + 1);}return res;}int gcd(int a, int b) {return b == 0 ? a : gcd(b, a % b);}
};
复杂度分析
时间复杂度: O ( n 2 × l o g m ) O(n^2 \times logm) O(n2×logm), m m m 为横纵坐标的最大差值,单次最大公约数计算时间复杂度为 O ( l o g m ) O(logm) O(logm)。
空间复杂度: O ( n ) O(n) O(n)。
写在最后
如果您发现文章有任何错误或者对文章有任何疑问,欢迎私信博主或者在评论区指出 💬💬💬。
如果大家有更优的时间、空间复杂度的方法,欢迎评论区交流。
最后,感谢您的阅读,如果有所收获的话可以给我点一个 👍 哦。