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
    输入的坐标均是有效的二维坐标

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/intersection-lcci
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

 

参考的思路来自于 刘汝佳 算法艺术与信息学竞赛 P357前后章节

class Solution {
public:
    double precision_n = 1e-6;//符合题目条件的浮点精度
    struct Point{
        double x,y;
        Point(){}//默认构造函数
        Point(double xx,double yy):x(xx),y(yy){}//自定义构造函数
        bool operator<(const Point p)const{//当交点重叠时,用于排序
            if(x==p.x){
                return y<p.y;
            }
            return x<p.x;
        }
    };
    //行列式,叉积
    double det(double x1, double y1, double x2, double y2){
        return x1*y2-x2*y1;
    }
    //三点叉积,用来计算有向面积
    double crossProduct(Point a, Point b, Point c){
        return det(b.x-a.x, b.y-a.y, c.x-a.x, c.y-a.y);
    }
    //浮点误差处理
    int dblcmp(double d){
        if(fabs(d)<precision_n){return 0;}
        return d>0?1:-1;
    }
    //点乘行列式
    double dotdet(double x1, double y1, double x2, double y2){
        return x1*x2+y1*y2;
    }
    //三点点乘
    double dotProduct(Point a, Point b, Point c){
        return dotdet(b.x-a.x, b.y-a.y, c.x-a.x, c.y-a.y);
    }
    //用来计算共线的情况下,a是否在b,c之间
    int betweenCmp(Point a, Point b, Point c){
        return dblcmp(dotProduct(a,b,c));
    }
    vector<double> intersection(vector<int>& start1, vector<int>& end1, vector<int>& start2, vector<int>& end2) {
        vector<double> result;
        Point result_p;
        Point a(start1[0],start1[1]),b(end1[0],end1[1]),c(start2[0],start2[1]),d(end2[0],end2[1]);
        //求成对叉积
        double s1,s2,s3,s4;
        int d1,d2,d3,d4;
        d1 = dblcmp(s1 = crossProduct(a,b,c));//a,b,c有向面积
        d2 = dblcmp(s2 = crossProduct(a,b,d));
        d3 = dblcmp(s3 = crossProduct(c,d,a));
        d4 = dblcmp(s4 = crossProduct(c,d,b));
        //规范相交,就是一个标准的叉叉
        if((d1^d2)==-2&&(d3^d4)==-2){//异或快速算法,1^-1=-2
            result_p.x = ((c.x)*s2-(d.x)*s1)/(s2-s1);//点分比例计算面积的方法
            result_p.y = ((c.y)*s2-(d.y)*s1)/(s2-s1);
            result.push_back(result_p.x);result.push_back(result_p.y);
        }
        //非规范相交,相交点可能是四点中的一个
        if(d1==0&&betweenCmp(c,a,b)<=0&&d2!=0)//c,a,b共线,且c在a,b之间,d,a,b不共线
        {
            result.push_back(c.x);result.push_back(c.y);
        }
        if(d2==0&&betweenCmp(d,a,b)<=0&&d1!=0)//d,a,b共线,且d在a,b之间,c,a,b不共线
        {
            result.push_back(d.x);result.push_back(d.y);
        }
        if(d3==0&&betweenCmp(a,c,d)<=0&&d4!=0)//a,c,d共线,且a在c,d之间
        {
            result.push_back(a.x);result.push_back(a.y);
        }
        if(d4==0&&betweenCmp(b,c,d)<=0&&d3!=0)//b,c,d共线,且b在c,d之间
        {
            result.push_back(b.x);result.push_back(b.y);
        }
        //重合
        if(d1==0&&d2==0){//四点共线
            //去掉分割开来的,两条共线的线的情况(虽然共线,但是完全不相交)
            if(!(betweenCmp(c,a,b)>0&&betweenCmp(d,a,b)>0&&betweenCmp(a,c,d)>0)){
                vector<Point> ps = {a,b,c,d};
                sort(ps.begin(),ps.end());
                result.push_back(ps[1].x);//选择位于中间的第二个点
                result.push_back(ps[1].y);
            }
        }
        return result;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值