leetcode
leetcode 101 ~ 150
直线上最多的点数

直线上最多的点数

难度:

标签:

题目描述

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

 

示例 1:

输入:points = [[1,1],[2,2],[3,3]]
输出:3

示例 2:

输入:points = [[1,1],[3,2],[5,3],[4,1],[2,3],[1,4]]
输出:4

 

提示:

  • 1 <= points.length <= 300
  • points[i].length == 2
  • -104 <= xi, yi <= 104
  • points 中的所有点 互不相同

代码结果

运行时间: 51 ms, 内存: 16.2 MB


/*
 * 思路:
 * 1. 使用Stream API遍历所有点。
 * 2. 对每对点计算斜率并统计相同斜率的点数。
 * 3. 使用最大公约数简化斜率表示。
 */
 
import java.util.*;
import java.util.stream.Collectors;
 
public class MaxPointsOnLineStream {
    public int maxPoints(int[][] points) {
        if (points.length <= 1) return points.length;
        return Arrays.stream(points).mapToInt(point -> {
            Map<String, Integer> slopeMap = new HashMap<>();
            int duplicates = 1;
            int verticals = 0;
            for (int[] other : points) {
                if (Arrays.equals(point, other)) continue;
                int dx = other[0] - point[0];
                int dy = other[1] - point[1];
                if (dx == 0 && dy == 0) {
                    duplicates++;
                } else if (dx == 0) {
                    verticals++;
                } else {
                    int gcd = gcd(dx, dy);
                    dx /= gcd;
                    dy /= gcd;
                    String slope = dx + "/" + dy;
                    slopeMap.merge(slope, 1, Integer::sum);
                }
            }
            int currentMax = slopeMap.values().stream().mapToInt(v -> v).max().orElse(verticals);
            return currentMax + duplicates;
        }).max().orElse(1);
    }
 
    private int gcd(int a, int b) {
        return b == 0 ? a : gcd(b, a % b);
    }
}
 

解释

方法:

这个题解是使用哈希表来解决直线上最多的点数问题。具体思路如下: 1. 如果点的个数小于等于2,直接返回点的个数即可,因为2个及以下的点必然在同一条直线上。 2. 对于点数大于2的情况,使用两重循环遍历所有点对。外层循环固定一个点,内层循环遍历其他点。 3. 对于每一对点(x1,y1)和(x2,y2),计算它们所在直线的一般式方程ax+by+c=0的系数a,b,c。 - 如果两点的x坐标相同,则直线方程为x=x1,系数为a=1,b=0,c=-x1。 - 如果两点的y坐标相同,则直线方程为y=y1,系数为a=0,b=1,c=-y1。 - 对于其他情况,可以通过两点式方程推导出a=1,b=(x1-x2)/(y2-y1),c=(x1*y2-x2*y1)/(y1-y2)。 4. 将直线方程的系数(a,b,c)作为键存入哈希表,对应的值为该直线上的点数。 5. 如果当前直线在哈希表中已存在,则将点数加1,并更新res为res和更新后点数的较大值。 6. 如果当前直线不在哈希表中,则将其加入哈希表,初始点数为2。 7. 遍历完所有点对后,res即为所求的最多在同一条直线上的点数。

时间复杂度:

O(n^2)

空间复杂度:

O(n^2)

代码细节讲解

🦆
在哈希表中作为键存储直线的(a, b, c)系数时,如何保证由于浮点数精度问题而导致的不同直线被错误地认为是相同的情况?
为了避免浮点数精度问题导致不同直线被错误地认为是相同的,可以通过规范化系数来解决。例如,可以将系数(a, b, c)除以它们的最大公约数,使系数为最简形式。此外,可以通过乘以一个常数或固定的精度比例来缩放系数,将浮点系数转换为整数。另一种方法是使用足够小的容忍度来比较两个浮点数,只有当它们的差异超过这个容忍度时,才认为它们不相等。
🦆
代码中对于两点式方程的推导是否存在误差,特别是当y1与y2非常接近但不相等时,如何处理精度问题以确保系数b和c的准确性?
确实,当y1和y2非常接近时,b和c的计算可能会因浮点数的精度问题而产生较大误差。解决这个问题的一种方法是使用更高精度的数据类型,如Python中的decimal.Decimal,这可以提供更高的精度和更好的数值稳定性。另外,可以通过增加逻辑来特别处理y1和y2非常接近的情况,例如使用不同的近似方法或者直接计算两点之间的角度来定义直线,避免直接计算斜率。
🦆
在计算每一对点形成的直线参数时,如果两点很接近但不完全相同,这种方法是否可能会因为数值计算问题而无法准确识别直线?
是的,如果两点非常接近但不完全相同,那么在计算其直线参数时可能会遇到数值计算问题,尤其是在计算斜率和截距时。这些问题可能导致相同直线的参数出现轻微的变化,被错误地识别为不同的直线。为了减少这种错误,可以使用前面提到的方法,例如提高浮点数的精度,或者引入容忍度来判断两组系数是否足够接近,从而认为它们表示同一条直线。
🦆
解决方案中对于点数少于等于2的情况,直接返回点的个数。这在所有输入点都相同的情况下是否仍然适用?
在所有输入点都相同的情况下,该解决方案返回的是输入点的个数,这是合理的。因为即便所有点都相同,它们也被认为是位于同一直线上。因此,对于点数少于等于2的任何情况,包括所有点相同的情况,直接返回点的个数是正确的处理方式。

相关问题

直线镜像

直线镜像