leetcode
leetcode 2801 ~ 2850
交点

交点

难度:

标签:

题目描述

Given two straight line segments (represented as a start point and an end point), compute the point of intersection, if any. If there's no intersection, return an empty array.

The absolute error should not exceed 10^-6. If there are more than one intersections, return the one with smallest X axis value. If there are more than one intersections that have same X axis value, return the one with smallest Y axis value.

Example 1:

Input: 
line1 = {0, 0}, {1, 0}
line2 = {1, 1}, {0, -1}
Output:  {0.5, 0}

Example 2:

Input: 
line1 = {0, 0}, {3, 3}
line2 = {1, 1}, {2, 2}
Output:  {1, 1}

Example 3:

Input: 
line1 = {0, 0}, {1, 1}
line2 = {1, 0}, {2, 1}
Output:  {}  (no intersection)

Note:

  • The absolute value of coordinate value will not exceed 2^7.
  • All coordinates are valid 2D coordinates.

代码结果

运行时间: 20 ms, 内存: 16.7 MB


/*
 * 思路:
 * 1. 使用Stream计算交点,遵循与Java解法相同的逻辑。
 */

import java.util.Optional;
import java.util.stream.Stream;

public class SolutionStream {
    public Optional<double[]> intersection(int[] start1, int[] end1, int[] start2, int[] end2) {
        double x1 = start1[0], y1 = start1[1];
        double x2 = end1[0], y2 = end1[1];
        double x3 = start2[0], y3 = start2[1];
        double x4 = end2[0], y4 = end2[1];

        double denom = (y4 - y3) * (x2 - x1) - (x4 - x3) * (y2 - y1);
        if (denom == 0) { // 平行或共线
            return Optional.empty();
        }

        double ua = ((x4 - x3) * (y1 - y3) - (y4 - y3) * (x1 - x3)) / denom;
        double ub = ((x2 - x1) * (y1 - y3) - (y2 - y1) * (x1 - x3)) / denom;

        return Stream.of(new double[] {x1 + ua * (x2 - x1), y1 + ua * (y2 - y1)})
                .filter(point -> ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1)
                .findFirst();
    }
}

解释

方法:

此题解首先通过直线方程和线段端点位置关系判断两线段是否平行或共线。如果平行且共线,再判断线段是否有重叠部分,并选出最小的交点。如果不平行,使用线性方程组来找到潜在的交点,并检查该点是否同时在两条线段上。

时间复杂度:

O(1)

空间复杂度:

O(1)

代码细节讲解

🦆
如何准确判断两条线段是否平行?在代码中是根据什么条件来判断两线段平行的?
在二维空间中,两条线段是否平行可以通过检查它们的斜率是否相等来判断。这可以通过交叉乘积来实现,因为交叉乘积在数值上等于两向量的斜率之差。在代码中,判断两线段平行的条件是 `(y4 - y3) * (x2 - x1) == (y2 - y1) * (x4 - x3)`。这个条件实际上检查了线段(start1, end1)和线段(start2, end2)的斜率是否相等。如果两线段之间的斜率相同,交叉乘积为零,这意味着没有垂直分量,因此两线段平行。
🦆
在处理共线情况时,如何确保找到的交点是X值最小的,如果X值相同,如何保证Y值最小?
当确定线段共线时,代码通过对线段端点进行比较来找出X值最小的交点,如果X值相同则比较Y值。首先,代码检查每个线段的端点是否在另一个线段上,使用辅助函数`inline`。然后,通过比较当前找到的交点`ans`与新考虑的端点,更新`ans`为较小的一个。具体实现为:在每次找到一个端点在另一线段上时,通过条件`if not ans or ans > [xk, yk]`来更新`ans`。这里`ans > [xk, yk]`利用了Python列表的比较规则:首先比较列表的第一个元素,如果相同则比较下一个元素。因此,这种方法首先确保X值是最小的,如果X值相同,则确保Y值是最小的。
🦆
代码中提到使用线性方程组来计算交点,能否详细解释这一计算过程?
当两线段不平行时,可以通过解线性方程组来找到它们的交点。首先,对于每条线段可以表示为参数方程:线段(start1, end1)表示为 `x1 + t1 * (x2 - x1)` 和 `y1 + t1 * (y2 - y1)`,线段(start2, end2)表示为 `x3 + t2 * (x4 - x3)` 和 `y3 + t2 * (y4 - y3)`。将这两个方程组合并整理得到两个方程关于`t1`和`t2`的表达式。然后解这个方程组来找到`t1`和`t2`的值。如果`0 <= t1 <= 1`和`0 <= t2 <= 1`,则交点在两条线段上。代码中的`t1`和`t2`的计算表达式分别是:`t1 = ((x1 - x3) * (y4 - y3) - (y1 - y3) * (x4 - x3)) / ((y2 - y1) * (x4 - x3) - (x2 - x1) * (y4 - y3))` 和 `t2 = ((x3 - x1) * (y2 - y1) - (x2 - x1) * (y3 - y1)) / ((y4 - y3) * (x2 - x1) - (y2 - y1) * (x4 - x3))`。如果这些值在0到1的范围内,这意味着交点确实位于两条线段的实际长度内。

相关问题