题目:
给定两条线段(表示为起点start = {X1, Y1}和终点end = {X2, Y2}),如果它们有交点,请计算其交点,没有交点则返回空值。
要求浮点型误差不超过10^-6。若有多个交点(线段重叠)则返回 X 值最小的点,X 坐标相同则返回 Y 值最小的点。
示例 1:
输入:
line1 = {0, 0}, {1, 0}
line2 = {1, 1}, {0, -1}
输出: {0.5, 0}
示例 2:
输入:
line1 = {0, 0}, {3, 3}
line2 = {1, 1}, {2, 2}
输出: {1, 1}
示例 3:
输入:
line1 = {0, 0}, {1, 1}
line2 = {1, 0}, {2, 1}
输出: {},两条线段没有交点
提示:
坐标绝对值不会超过 2^7
输入的坐标均是有效的二维坐标
代码:
class Solution:
def intersection(self, start1, end1, start2, end2):
x1, y1, x2, y2, x3, y3, x4, y4 = *start1, *end1, *start2, *end2
det = lambda a, b, c, d: a * d - b * c
d = det(x1 - x2, x4 - x3, y1 - y2, y4 - y3)
p = det(x4 - x2, x4 - x3, y4 - y2, y4 - y3)
q = det(x1 - x2, x4 - x2, y1 - y2, y4 - y2)
if d != 0:
lam, eta = p / d, q / d
if not (0 <= lam <= 1 and 0 <= eta <= 1): return []
return [lam * x1 + (1 - lam) * x2, lam * y1 + (1 - lam) * y2]
if p != 0 or q != 0: return []
t1, t2 = sorted([start1, end1]), sorted([start2, end2])
if t1[1] < t2[0] or t2[1] < t1[0]: return []
return max(t1[0], t2[0])
想法:
第一个技巧:确定两点之间的线段,假设两个端点(x1,y1)与(x2,y2),那么两点之间的线段满足:
所以给定直线上任意一点,如果lambda不在0到1之间,那么此点不在线段上;
第二个技巧:如何确定方程组。根据上下文得知,关键在于求系数,所以方程可以写为:
等价于
第三个技巧,如何解方程组。经验之见,手动求解方程组少用消元法!否则一不小心就会贡献错误答案,推荐使用Cramer法则,因为Cramer法则只在最后一步用除法,中途不会出现除0和精度的错误;
其中,
假设,判断条件为:
- 如果D!=0,那么方程组有唯一解,
如果lambda和n都在0-1之间,那么返回交点;否则交点不在线段上,返回空;
- 如果D==0,但是P或Q不等于0,那么方程无解,不存在交点,返回空;
- 否则方程组有无穷多解;
核心在于:参数方程和卡兰姆法则