Given n points on a 2D plane, find the maximum number of points that lie on the same straight line.
Example 1:
Input: [[1,1],[2,2],[3,3]]
Output: 3
Explanation:
^
|
| o
| o
| o
+------------->
0 1 2 3 4
Example 2:
Input: [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
Output: 4
Explanation:
^
|
| o
| o o
| o
| o o
+------------------->
0 1 2 3 4 5 6
NOTE: input types have been changed on April 15, 2019. Please reset to default code definition to get new method signature.
SOLUTION
- 暴力解法,依次掃描每個點,對每個點都依次掃描其后面的所有點。只要斜率相同的就認為是在同一條直線上,用一個
Hashmap
來存儲每個斜率和其出現的次數。找到最大的次數即可。 - 但需要處理幾種特殊情況:
- 兩個點重復,用一個
duplicate
變量記錄重合的點。最后只需要和哈希表中的數字相加即為共線點的總數 - 垂直線 和 水平線
- 兩個點重復,用一個
- 斜率:
dy/dx = (y2 -y1) / (x2 - x1)
, 即使用double也不一定準備,所以應該避免除法。- 把除數和被除數都保存下來,不做除法。
- 但是要讓這兩數分別除以它們的最大公約數,例如8和4,4和2,2和1,這三組商相同的數就都會存到一個映射里面。
- 求 GCD 的函數: 用遞歸, 經典解法
public int getGCD (int dy, int dx) {
return dx == 0 ? dy : getGCD (dx, dy % dx);
}
代碼
class Solution {
public int maxPoints(int[][] points) {
if (points == null || points.length == 0 || points[0].length == 0) {
return 0;
}
// Map必須放在循環內,因為求的是基于每個點,對其以后的點求斜率,找斜率出現的最大值。如果放在外面,那么可能出現重復計算
// 比如[[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]], 在計算【3,2】點的時候,后面【2,3】【4,1】,【1,4】都已經計算過了,斜率已經累加
// 如果不清零,那么當計算【2,3】點的時候,【2,3】【1,4】的斜率又會被累加一次,重復!
// Map<Map<Integer, Integer>, Integer> slopVsCount = new HashMap<> ();
int maxPoints = 0;
for (int i = 0; i < points.length; i++) {
Map<Map<Integer, Integer>, Integer> slopVsCount = new HashMap<> ();
int[] point1 = points[i];
int duplicate = 1;
int localMaxPoints = 0;
for (int j = i + 1; j < points.length; j++) {
int [] point2 = points [j];
if (point1[0] == point2[0] && point1[1] == point2[1]) {
duplicate ++;
} else {
Map<Integer, Integer> slope = getSlope (point1, point2);
int count = slopVsCount.getOrDefault (slope, 0);
count++;
// System.out.println (count);
slopVsCount.put (slope, count);
localMaxPoints = Math.max (localMaxPoints, count);
}
}
//System.out.println (localMaxPoints);
maxPoints = Math.max (maxPoints, localMaxPoints + duplicate);
}
return maxPoints;
}
public Map<Integer, Integer> getSlope (int[] point1, int[] point2) {
Map<Integer, Integer> result = new HashMap<> ();
int dy = point2[1] - point1[1];
int dx = point2[0] - point1[0];
// vertical line
if (dx == 0) {
result.put (0, point1[0]);
return result;
}
// horizontal line
if (dy == 0) {
result.put (point1[1], 0);
return result;
}
// for other slopes
int gcd = getGCD (dy, dx);
// System.out.println ("point1: " + point1[0] + " " + point1[1]);
// System.out.println ("point2: " + point2[0] + " " + point2[1]);
// System.out.println ("Slope --- dy: " + (dy / gcd) + " dx: " + (dx / gcd ));
result.put (dy / gcd, dx / gcd );
return result;
}
public int getGCD (int dy, int dx) {
return dx == 0 ? dy : getGCD (dx, dy % dx);
}
}