一、题目

给你一个数组 points ,其中 points[i] = [x, y] 表示 X-Y 平面上的一个点。求最多有多少个点在同一条直线上。

点击查看原题
难度级别: 困难

二、思路

1)哈希表+斜率表达

首先,考虑在同一条直线上的点,其两两之间斜率一定相等,普通的斜率表达如下所示:
149. 直线上最多的点数-每日一题 - 图1
在代码中令:
149. 直线上最多的点数-每日一题 - 图2
因为比值相等时,其最简形式一定相等,求出diffXdiffY的最大公约数(这里使用辗转相除法),并除以最大公约数。斜率有负值的情况,但不知道是分子还是分母,假定diffX不能小于0,小于的话就将分子分母取相反数。
因为-10 <= x, y <= 10,斜率采用另一种表达方式,kVal`` = diffY + diffX*``100000,将diffX移到高位进行表示。
使用两层for循环,选择一个点对其他所有点进行斜率计算,每次选择一个点都建立新的哈希表,该哈希表记录经过选取点所有直线斜率和直线上点的数量。

三、代码

1)哈希表+斜率表达

  1. class Solution {
  2. public int maxPoints(int[][] points) {
  3. int ans = 1;
  4. for (int k = 0; k < points.length; k++) {
  5. Map<Integer, Integer> map = new HashMap();
  6. for (int i = 0; i < points.length; i++) {
  7. if (i == k) { // 跳过自身点
  8. continue;
  9. }
  10. int diffX = points[i][0] - points[k][0]; // 获取坐标差值
  11. int diffY = points[i][1] - points[k][1];
  12. int gcdVal = gcd(Math.abs(diffX), Math.abs(diffY)); // 获取最大公约数
  13. diffX = diffX / gcdVal;
  14. diffY = diffY / gcdVal;
  15. if (diffX < 0) { // 指定diffX不能为小于0的数
  16. diffX = -diffX;
  17. diffY = -diffY;
  18. }
  19. int kVal = diffY + diffX*100000; // 通过将diffX移动到高位形成唯一的斜率编码
  20. map.put(kVal, map.getOrDefault(kVal, 1) + 1);
  21. }
  22. for (Map.Entry<Integer, Integer> entry : map.entrySet()) {
  23. ans = Math.max(ans, entry.getValue());
  24. }
  25. }
  26. return ans;
  27. }
  28. private int gcd(int a, int b) { // 辗转相除法
  29. return b != 0 ? gcd(b, a%b) : a;
  30. }
  31. }

n为点总数,m为横纵坐标差最大值,时间复杂度O(n^2``*logm),空间复杂度为O(n)