welcome to my blog
LeetCode Top Interview Questions 149. Max Points on a Line (Java版; Hard)
题目描述
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
第一次做; 核心: 用分数表示斜率; 根据两个点的四种关系进行讨论; 夯实基础: 辗转相除法求最大公因数
/*
核心1:要用分数表示斜率, 不用能小数, 因为会有精度损失;
核心2:如何统计共线的点的个数
重要基础: 求两个树的最大公因数, 递归; 辗转相除法
*/
class Solution {
public int maxPoints(int[][] points) {
if(points==null || points.length==0 || points[0]==null || points[0].length==0)
return 0;
//小于等于两个点, 直接返回点的数量即可
if(points.length<=2)
return points.length;
//key是斜率的分子; value是该斜率的的分母, 以及该分数对应的斜率的个数
HashMap<Integer, HashMap<Integer, Integer>> map = new HashMap<>();
//
int n=points.length;
int res = 0;
for(int i=0; i<n-1; i++){
//共线的4种大可能:两个点重合; 两个点横坐标相同; 两个点纵坐标相同; 两个点横纵坐标都不同
//考虑points[i]在内, 与points[i]重合的点, 这样的点有多少个
int sameXY = 1;
//不考虑points[i]在内, 与points[i]横坐标相同的点, 这样的点有多少个
int sameX = 0;
//不考虑points[i]在内, 与points[i]纵坐标相同的点, 这样的点有多少个
int sameY = 0;
//line表示: 不考虑points[i]在内, 当和points[i]呈某一斜率, 共线的点最多时, 此时与points[i]共线的点的数量
int line = 0;
for(int j=i+1; j<n; j++){
int dy = points[i][1] - points[j][1];
int dx = points[i][0] - points[j][0];
//具体处理共线的4中可能
if(dx==0 && dy==0)
sameXY++;
else if(dx==0 && dy!=0)
sameX++;
else if(dx!=0 && dy==0)
sameY++;
else{
int gc = gcd(dy, dx);
//斜率化简后的分子
int numerator = dy/gc;
//斜率化简后的分母
int denominator = dx/gc;
if(!map.containsKey(numerator))
map.put(numerator, new HashMap<Integer,Integer>());
HashMap<Integer, Integer> hm = map.get(numerator);
if(!hm.containsKey(denominator))
hm.put(denominator, 0);
hm.put(denominator, hm.get(denominator)+1);
/*
* 核心: 不能在这里更新res, 这里应该记录和points[i]构成非0斜率的点的数量最大值, 然后在内循环结束后再更新res,
* 否则无法通过示例:[[0,0],[1,1],[0,0]], 正确输出:3; 错误输出2, 因为在这里更新res的时候还没有遇到第二个[0,0],
* 遇到第二个[0,0]时, 所以少考虑了一个重复点
* */
line = Math.max(line, hm.get(denominator));
}
}
//清空map, 因为map中的数据仅对points[i]有效
map.clear();
//更新结果; 找出sameX,sameY,line中的最大值, 然后加上sameXY作为points[i]时的最大值, 如果该最大值比res大就更新res
res = Math.max(res, Math.max(sameX, Math.max(sameY, line)) + sameXY);
}
return res;
}
public int gcd(int a, int b){
return b==0? a : gcd(b, a%b);
}
}