本文涉及知识点
数学
计算几何
LeetCode面试题 16.03. 交点
给定两条线段(表示为起点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
2^727
输入的坐标均是有效的二维坐标
计算几何
用叉乘判断线段所在直线是否平行。
一,直线的表达方式,斜截式。y=kx+b。无法表达垂直于x轴的直线。
二,截距式。x
a
+
y
b
=
1
\frac{x}{a}+\frac{y}{b}=1ax+by=1,无法表达平行于坐标轴的直线。
三,一般形式a
x
+
b
y
+
c
=
0
ax+by+c=0ax+by+c=0,表示所有直线,缺点不直观。
四,参数方程。x=x0+t△
\triangle△x,y=y0+t△
\triangle△y。
假设是线段(x1,y1)和(x2,y2)则:
则{
x
=
x
1
+
t
(
x
2
−
x
1
)
y
=
y
1
+
t
(
y
2
−
y
1
)
\begin{cases} x=x1+t(x2-x1) \\ y=y1+t(y2-y1) \\ \end{cases}{x=x1+t(x2−x1)y=y1+t(y2−y1)
∀
(
x
,
y
)
求出的
t
\forall (x,y)求出的t∀(x,y)求出的t如果相同,则在直线上。如果0
≤
t
≤
1
0 \le t \le 10≤t≤1在线段上。
平行
如果两条线段对应直线不共线,则返回空。
4个端点。就是如果共线,符合条件一定
否则返回空。
判断(x,y)是否在线段(x1,y1)(x2,y2)上。
先判断是在直线上
情况一: x
1
≠
x
2
,
y
1
≠
y
2
x1 \neq x2,y1 \neq y2x1=x2,y1=y2
t
1
=
(
x
−
x
1
)
÷
(
x
2
−
x
1
)
t1= (x-x1)\div (x2-x1)t1=(x−x1)÷(x2−x1)
t
2
=
(
y
−
y
1
)
÷
(
y
2
−
y
1
)
t2=(y-y1)\div (y2-y1)t2=(y−y1)÷(y2−y1)
假如t1和t2相等,则:(
x
−
x
1
)
(
y
2
−
y
1
)
=
=
(
y
−
y
1
)
(
x
2
−
x
1
)
(x-x1)(y2-y1)==(y-y1)(x2-x1)(x−x1)(y2−y1)==(y−y1)(x2−x1)式子一
情况二 x
1
=
=
x
2
,
y
1
≠
y
2
x1==x2,y1 \neq y2x1==x2,y1=y2
x必须等于x1,和式子一等效。
情况三: x
1
≠
x
2
,
y
1
=
=
y
2
x1 \neq x2,y1==y2x1=x2,y1==y2
y必须等于y1。
结论:式子一可能判断,点是否在直线上。
*扩展:令(x,y)是P,(x1,y1)和(x2,y2)是P1,P2,式子一就是P
P
1
⃗
×
P
2
P
1
⃗
=
=
0
\vec{PP1}\times \vec{P2P1} == 0PP1×P2P1==0PP1和PP2平行,说明P在直线P1P2上。
判断点是否在线段上
( x − x 1 ) ( x − x 2 ) ≤ 0 且 ( y − y 1 ) ( y − y 2 ) ≤ 0 (x-x1)(x-x2)\le 0且(y-y1)(y-y2) \le 0(x−x1)(x−x2)≤0且(y−y1)(y−y2)≤0
不平行。
令第一条线段的两个端点为(x1,y1)和(x2,y2),第二条线段的两个端点为(x3,y3)和(x4,y4)。
令交点为(x,y)则:
x
=
x
1
+
t
1
(
x
2
−
x
1
)
=
x
3
+
t
2
(
x
4
−
x
3
)
x=x1+t1(x2-x1)=x3+t2(x4-x3)x=x1+t1(x2−x1)=x3+t2(x4−x3)式子一
y
=
y
1
+
t
1
(
y
2
−
y
1
)
=
y
3
+
t
2
(
y
4
−
y
3
)
y=y1+t1(y2-y1)=y3+t2(y4-y3)y=y1+t1(y2−y1)=y3+t2(y4−y3)式子二
情况一:x
1
≠
x
2
且
y
1
≠
y
2
x1 \neq x2 且 y1 \neq y2x1=x2且y1=y2
式子一乘以(y2-y1)
(
x
1
−
x
3
)
(
y
2
−
y
1
)
+
t
1
(
x
2
−
x
1
)
(
y
2
−
y
1
)
=
t
2
(
x
4
−
x
3
)
(
y
2
−
y
1
)
(x1-x3)(y2-y1)+t1(x2-x1)(y2-y1)=t2(x4-x3)(y2-y1)(x1−x3)(y2−y1)+t1(x2−x1)(y2−y1)=t2(x4−x3)(y2−y1)
式子二乘以(x2-x1)
(
y
1
−
y
3
)
(
x
2
−
x
1
)
+
t
1
(
x
2
−
x
1
)
(
y
2
−
y
1
)
=
t
2
(
y
4
−
y
3
)
(
x
2
−
x
1
)
(y1-y3)(x2-x1)+t1(x2-x1)(y2-y1)=t2(y4-y3)(x2-x1)(y1−y3)(x2−x1)+t1(x2−x1)(y2−y1)=t2(y4−y3)(x2−x1)
两者相减:
(
x
1
−
x
3
)
(
y
2
−
y
1
)
−
(
y
1
−
y
3
)
(
x
2
−
x
1
)
=
t
2
[
(
x
4
−
x
3
)
(
y
2
−
y
1
)
−
(
y
4
−
y
3
)
(
x
2
−
x
1
)
]
(x1-x3)(y2-y1)-(y1-y3)(x2-x1)=t2[(x4-x3)(y2-y1)-(y4-y3)(x2-x1)](x1−x3)(y2−y1)−(y1−y3)(x2−x1)=t2[(x4−x3)(y2−y1)−(y4−y3)(x2−x1)]
→
t
2
=
[
(
x
1
−
x
3
)
(
y
2
−
y
1
)
−
(
y
1
−
y
3
)
(
x
2
−
x
1
)
]
÷
[
(
x
4
−
x
3
)
(
y
2
−
y
1
)
−
(
y
4
−
y
3
)
(
x
2
−
x
1
)
]
\rightarrow t2 =[(x1-x3)(y2-y1)-(y1-y3)(x2-x1)] \div [(x4-x3)(y2-y1)-(y4-y3)(x2-x1)]→t2=[(x1−x3)(y2−y1)−(y1−y3)(x2−x1)]÷[(x4−x3)(y2−y1)−(y4−y3)(x2−x1)]式子三
如果分母为0,根据叉乘为0,则两矢量方向相同或想法,即两直线平行。
同理:
t
1
=
[
(
x
3
−
x
1
)
(
y
4
−
y
3
)
−
(
y
3
−
y
1
)
(
x
4
−
x
3
)
]
÷
[
(
x
2
−
x
1
)
(
y
4
−
y
3
)
−
(
x
4
−
x
3
)
(
y
2
−
y
1
)
]
t1=[(x3-x1)(y4-y3)-(y3-y1)(x4-x3)]\div[(x2-x1)(y4-y3)-(x4-x3)(y2-y1)]t1=[(x3−x1)(y4−y3)−(y3−y1)(x4−x3)]÷[(x2−x1)(y4−y3)−(x4−x3)(y2−y1)]式子四
情况二:x1 == x2,y
1
≠
y
2
y1 \neq y2y1=y2
即线段一,垂直于x轴。线段二不垂直于x轴,即x
4
≠
x
3
x4 \neq x3x4=x3。
x1=x3+t2(x4-x3)→
t
2
=
(
x
1
−
x
3
)
÷
(
x
4
−
x
3
)
\rightarrow t2=(x1-x3)\div (x4-x3)→t2=(x1−x3)÷(x4−x3)
对式子三,用x1替换x2。
t
2
=
(
x
1
−
x
3
)
(
y
2
−
y
1
)
÷
(
x
4
−
x
3
)
(
y
2
−
y
1
)
=
(
x
1
−
x
3
)
÷
(
x
4
−
x
3
)
t2 =(x1-x3)(y2-y1)\div (x4-x3)(y2-y1)=(x1-x3)\div(x4-x3)t2=(x1−x3)(y2−y1)÷(x4−x3)(y2−y1)=(x1−x3)÷(x4−x3)即t2无需特殊处理。
情况三:y1==y2,x
1
≠
x
2
x1 \neq x2x1=x2,即线段一垂直于y轴。线段二不平行于y轴。y
3
≠
y
4
y3 \neq y4y3=y4
对式子二,y1代替y2。y
1
=
y
3
+
t
2
(
y
4
−
y
3
)
→
t
2
=
(
y
1
−
y
3
)
÷
(
y
4
−
y
3
)
y1=y3+t2(y4-y3)\rightarrow t2=(y1-y3)\div (y4-y3)y1=y3+t2(y4−y3)→t2=(y1−y3)÷(y4−y3)
对于式子三,用y1代替y2。−
(
y
1
−
y
3
)
(
x
2
−
x
1
)
÷
−
(
y
4
−
y
3
)
(
x
2
−
x
1
)
=
(
y
1
−
y
3
)
÷
(
y
4
−
y
3
)
-(y1-y3)(x2-x1)\div-(y4-y3)(x2-x1)=(y1-y3)\div(y4-y3)−(y1−y3)(x2−x1)÷−(y4−y3)(x2−x1)=(y1−y3)÷(y4−y3)
即t2无需特殊处理。
情况四:y
1
=
=
y
2
,
x
1
=
=
x
2
y1 == y2 ,x1 == x2y1==y2,x1==x2,点重合,与提议矛盾。
总结:计算t2无需特殊处理,t2就可以计算出交点。
代码
核心代码
int CrossMul(int x1, int y1, int x2, int y2) {
return x1*y2 - x2*y1;
}
bool PointInLine(int x, int y, int x1, int y1, int x2, int y2) {
return 0 == CrossMul(x - x1, y - y1, x - x2, y - y2);
}
bool PointInSegMent(int x, int y, int x1, int y1, int x2, int y2) {
if (!PointInLine(x, y, x1, y1, x2, y2)) { return false; }
return ((x - x1) * (x - x2) <= 0) && ((y - y1)*(y - y2) <= 0);
}
class Solution {
public:
vector<double> intersection(vector<int>& start1, vector<int>& end1, vector<int>& start2, vector<int>& end2) {
const int x1 = start1[0], x2 = end1[0], x3 = start2[0], x4 = end2[0];
const int y1 = start1[1], y2 = end1[1], y3 = start2[1], y4 = end2[1];
const int iCM = CrossMul(x4 - x3, y4 - y3, x2 - x1, y2 - y1);
if (0 != iCM) {//不处理平行
double t2 = CrossMul(x1 - x3, y1 - y3, x2 - x1, y2 - y1)/(double)iCM;
const double x = x3 + t2 * (x4 - x3);
const double y = y3 + t2 * (y4 - y3);
if (((x - x1) * (x - x2) <= 0) && ((x - x3) * (x - x4) <= 0) && ((y - y1) * (y - y2) <= 0) && ((y - y3) * (y - y4) <= 0)) {
return {x,y};
}
return {};
}
vector<vector<double>> ans;
if (PointInSegMent(x1, y1, x3, y3, x4, y4)) {
ans.emplace_back(vector<double>{ (double)x1,(double)y1 });
}
if (PointInSegMent(x2, y2, x3, y3, x4, y4)) {
ans.emplace_back(vector<double>{ (double)x2, (double)y2 });
}
if (PointInSegMent(x3, y3, x1, y1, x2, y2)) {
ans.emplace_back(vector<double>{ (double)x3, (double)y3 });
}
if (PointInSegMent(x4, y4, x1, y1, x2, y2)) {
ans.emplace_back(vector<double>{ (double)x4, (double)y4 });
}
sort(ans.begin(), ans.end());
return ans.size() ? ans[0] : vector<double>{};
}
};

扩展阅读
| 我想对大家说的话 |
|---|
| 工作中遇到的挑战,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。 |
| 学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作 |
| 高效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注 |
| 员工说:手艺至上,老板不信;投资人的代表说:技术至上,老板会信。 |
| 闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。 |
| 子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。 |
| 如果程序是一条龙,那算法就是他的是睛 |
| 失败+反思=成功 成功+反思=成功 |
视频课程
先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771
如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176
测试环境
操作系统:win7 开发环境: VS2019C++17
或者 操作系统:win10 开发环境: VS2022C++17
如无特殊说明,本算法用**C++**实现。
浙公网安备 33010602011771号