【CODE】线段交点—Intersection LCCI

面试题 16.03. 交点

难度困难17收藏分享切换为英文关注反馈

给定两条线段(表示为起点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
  • 输入的坐标均是有效的二维坐标

使用直线的一般式求解,线段的函数:Ax+By+C=0
需要实现的函数:
(1)求出A、B、C:
    y=(y2-y1)/(x2-x1)*(x-x2)+y2
    所以 A=y2-y1, B=x1-x2, C=x2y1-x1y2
(2)判断两个线段是否平行:
    A1/B1=A2/B2, 避免除以0, A1*B2=A2*B1
(3)求并行线段的x坐标最小的交点:
    如果交点存在,那么一定是两个线段的一个端点,判断端点是否在另一个线段上
(4)判断点是否在线段上:
    如果两个端点是s和e,如果p在线段上,那么dis(s,p)+dis(p,e)=dis(s,e)
(5)不平行线段的交点
    A1x+B1y+C1=0, A2x+B2y+C2=0
    A1*A2*x+B1*A2*y+C1*A2=0
    A2*A1*x+B2*A1*y+C2*A1=0
    y = (C1 * A2 - C2 * A1) / (A1 * B2 - A2 * B1)
    同理,x = (C2 * B1 - C1 * B2) / (A1 * B2 - A2 * B1)
    如果(x,y)在两线段上,则(x,y)即为答案,否则交点不存在

#include"pch.h"
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
/*执行用时 :4 ms, 在所有 C++ 提交中击败了71.90%的用户
内存消耗 :11.5 MB, 在所有 C++ 提交中击败了100.00%的用户*/
vector<double> getABC(const vector<int> &point1, const vector<int> &point2) {
	double A = point2[1] - point1[1];
	double B = point1[0] - point2[0];
	double C = point2[0] * point1[1] - point1[0] * point2[1];
	return vector<double>{ A, B, C };
}//求出A、B、C
bool ifparallel(double A1, double B1, double A2, double B2) {
	if (A1*B2 == A2 * B1) return true;
	return false;
}//判断两个线段是否平行
template<typename T1, typename T2, typename T3>
bool ifinline(const T1 & s, const T2 & e, const T3 &p) {
	double d1 = sqrt((p[0] - s[0])*(p[0] - s[0]) + (p[1] - s[1])*(p[1] - s[1]));
	double d2 = sqrt((p[0] - e[0])*(p[0] - e[0]) + (p[1] - e[1])*(p[1] - e[1]));
	double d3 = sqrt((e[0] - s[0])*(e[0] - s[0]) + (e[1] - s[1])*(e[1] - s[1]));
	//要求浮点型误差不超过10^-6
	if (fabs(d1 + d2 - d3) <= 1e-7) return true;
	return false;
}//判断点是否在线段上
vector<double> getparllelnode(vector<int>& start1, vector<int>& end1, vector<int>& start2, vector<int>& end2) {
	vector<vector<double> > res;
	if (ifinline(start1, end1, start2)) res.push_back(vector<double>{double(start2[0]), double(start2[1])});
	if (ifinline(start1, end1, end2)) res.push_back(vector<double>{double(end2[0]), double(end2[1])});
	if (ifinline(start2, end2, start1)) res.push_back(vector<double>{double(start1[0]), double(start1[1])});
	if (ifinline(start2, end2, end1)) res.push_back(vector<double>{double(end1[0]), double(end1[1])});
	if (res.size() == 0) return vector<double>{};
	sort(res.begin(), res.end(), [](const vector<double> &a, const vector<double> &b)->bool {
		return a[0] < b[0];//求x最小的那个坐标
	});
	return res[0];//返回这个坐标
}//求并行线段的x坐标最小的交点
vector<double> intersection(vector<int>& start1, vector<int>& end1, vector<int>& start2, vector<int>& end2) {
	vector<double> p1 = getABC(start1, end1);
	vector<double> p2 = getABC(start2, end2);
	if (ifparallel(p1[0], p1[1], p2[0], p2[1])) {
		return getparllelnode(start1, end1, start2, end2);
	}//如果平行
	//不平行线段的交点
	//y = (C1 * A2 - C2 * A1) / (A1 * B2 - A2 * B1)
	//x = (C2 * B1 - C1 * B2) / (A1 * B2 - A2 * B1)
	double y = (p1[2] * p2[0] - p2[2] * p1[0]) / (p1[0] * p2[1] - p2[0] * p1[1]);
	double x = (p2[2] * p1[1] - p1[2] * p2[1]) / (p1[0] * p2[1] - p2[0] * p1[1]);
	vector<double> tmp = { x,y };
	if (ifinline(start1, end1, tmp) && ifinline(start2, end2, tmp)) {
		return tmp;
	}
	return vector<double>{};
}
int main() {
	vector<int> s1 = { 0,0 }; vector<int> e1 = { 1,0 };
	vector<int> s2 = { 1,1 }; vector<int> e2 = { 0,-1 };
	vector<double> res=intersection(s1,e1,s2,e2);
	cout << res[0] << " " << res[1] << endl;
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值