From b183a0a0ee3a72a48ce317882f7d74f3f684eae8 Mon Sep 17 00:00:00 2001 From: ShusenTang Date: Mon, 16 Mar 2020 22:47:24 +0800 Subject: [PATCH] add 149. Max Points on a Line :beer: --- README.md | 1 + solutions/149. Max Points on a Line.md | 93 ++++++++++++++++++++++++++ 2 files changed, 94 insertions(+) create mode 100644 solutions/149. Max Points on a Line.md diff --git a/README.md b/README.md index a6a37e9..bdd6689 100644 --- a/README.md +++ b/README.md @@ -137,6 +137,7 @@ My LeetCode solutions with Chinese explanation. 我的LeetCode中文题解。 | 144 |[Binary Tree Preorder Traversal](https://leetcode.com/problems/binary-tree-preorder-traversal/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/144.%20Binary%20Tree%20Preorder%20Traversal.md)|Medium| | | 146 |[LRU Cache](https://leetcode.com/problems/lru-cache/)|[C++](solutions/146.%20LRU%20Cache.md)|Medium| | | 148 |[Sort List](https://leetcode.com/problems/sort-list/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/148.%20Sort%20List.md)|Medium| | +| 149 |[Max Points on a Line](https://leetcode.com/problems/max-points-on-a-line/)|[C++](solutions/149.%20Max%20Points%20on%20a%20Line.md)|Hard| | | 150 |[Evaluate Reverse Polish Notation](https://leetcode.com/problems/evaluate-reverse-polish-notation/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/150.%20Evaluate%20Reverse%20Polish%20Notation.md)|Medium| | | 151 |[Reverse Words in a String](https://leetcode.com/problems/reverse-words-in-a-string/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/151.%20Reverse%20Words%20in%20a%20String.md)|Medium| | | 152 |[Maximum Product Subarray](https://leetcode.com/problems/maximum-product-subarray/)|[C++](https://github.com/ShusenTang/LeetCode/blob/master/solutions/152.%20Maximum%20Product%20Subarray.md)|Medium| | diff --git a/solutions/149. Max Points on a Line.md b/solutions/149. Max Points on a Line.md new file mode 100644 index 0000000..48eda06 --- /dev/null +++ b/solutions/149. Max Points on a Line.md @@ -0,0 +1,93 @@ +# [149. Max Points on a Line](https://leetcode.com/problems/max-points-on-a-line/) + +# 思路 + +给定一些二维的点,问共线的点最多有多少个。 + +## 思路一 + +我们知道,**一个点P和斜率k确定一条直线**。所以我们可以用两层循环,外层循环枚举所有点P,内层循环遍历其他点计算斜率k,同时用hash记录每个k出现了多少次。但这样会存在一个问题那就是斜率k的精度问题,所以我们考虑不将k算成小数而是用最简分数表示k,为了化简分数,我们只需要将分子和分母除以二者最大公倍数即可。 + +有两个注意点: +1. 内外层循环的两个点可能重合,此时应该跳过,跳过之前要用一个变量duplicate累积重复的次数,因为最终记录结果时这个点要算多次。 + +2. 算斜率时分子分母可能为负号,注意 (-1)/2 和1/(-2)的斜率都是-0.5,所以为了避免这种情况我们统一对其取绝对值,最后将可能存在的负号添加在分母上。 + +辗转相除法求a和b的最大公约数时间复杂度为log(a+b),是很快的,不考虑这个时间。如果用的hash而不是treemap那么查询时间复杂度为O(1),那么总的复杂度就是两层循环,为O(n^2)。 + +## 思路二 + +我们知道,**两个(不重合)的点也可以确定一条直线**,所以我们可以(用一个两层循环)遍历所有点对,然后再遍历其他点看这三点是否在一条直线上,所以总的是个三层循环。 + +如何判断三点相等呢,假设三个点分别是`(x1,y1), (x2,y2), (x3,y3)`;所以第一个点和第二个点可组成向量`v1 = (x1-x2, y1-y2) = (dx1, dy1)`,所以第一个点和第三个点可组成向量`v2=(x1-x3, y1-y3) = (dx2,dy2)`,要使三个点共线,那么向量`v1`和`v2`应该平行,而且要避免除法,所以有`dx1 * dy2 - dy1 * dx2 = 0`(这个式子难理解的话可以转换成v1与v2的法向量垂直,两向量垂直的条件是內积为0)。 + +同样要注意重合点,另外第三层循环是从0开始的! + +时间复杂度O(n^3),亲测确实比思路一慢一些。 + +# C++ +## 思路一 +``` C++ +class Solution { +private: + int gcd(int a, int b){ + return b == 0 ? a : gcd(b, a % b); + } + +public: + int maxPoints(vector>& points) { + int n = points.size(); + int res = min(2, n); + for(int i = 0; i < n; i++){ + int duplicate = 1; + map, int>mp; + for(int j = i+1; j < n; j++){ + int dx = points[j][0] - points[i][0]; + int dy = points[j][1] - points[i][1]; // 斜率k = dy/dx + if(dx == 0 && dy == 0) duplicate++; + else{ + int neg = (dx < 0 && dy > 0) || (dx > 0 && dy < 0) ? -1 : 1; + dx = abs(dx); dy = abs(dy); + int g = gcd(dx, dy); + mp[{neg * dx / g, dy / g}]++; + } + } + res = max(res, duplicate); + for(auto it: mp) res = max(res, duplicate + it.second); + } + return res; + } +}; +``` + +## 思路二 + +``` C++ +class Solution { +public: + int maxPoints(vector>& points) { + int n = points.size(); + long long dx1, dy1, dx2, dy2; + int cur, res = min(2, n); + for(int i = 0; i < n; i++){ + int duplicate = 1; + for(int j = i + 1; j < n; j++){ + dx1 = points[i][0] - points[j][0]; + dy1 = points[i][1] - points[j][1]; + if(dx1 == 0 && dy1 == 0) duplicate++; + else{ + cur = 0; + for(int k = 0; k < n; k++){ // 这里从0开始的!! + dx2 = points[i][0] - points[k][0]; + dy2 = points[i][1] - points[k][1]; + if(dx1*dy2 == dy1*dx2) cur++; + } + res = max(res, cur); + } + } + res = max(res, duplicate); + } + return res; + } +}; +``` \ No newline at end of file