面试金典——交点

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

A:
这个题……纯粹就是数学题。
参考:https://leetcode-cn.com/problems/intersection-lcci/solution/xiang-xi-fen-lei-tao-lun-he-bing-xiang-si-qing-kua/

    public double[] intersection(int[] start1, int[] end1, int[] start2, int[] end2) {
        double x = 0, y = 0;
        double  x1 = start1[0], y1 = start1[1],
                x2 = end1[0],   y2 = end1[1],
                x3 = start2[0], y3 = start2[1],
                x4 = end2[0],   y4 = end2[1];
        // 第一条直线平行于 X 轴
        if (x1 - x2 == 0) {
            // 第二条直线也平行于 X 轴
            if (x3 - x4 == 0) {
                // 两条线段有重叠:同一直线,且一个端点在另一条线段之内
                if (x1 == x3 && Math.max(y1, y2) >= Math.min(y3, y4) && Math.min(y1, y2) <= Math.max(y3, y4))
                    return new double[] {x1, Math.max(Math.min(y1, y2), Math.min(y3, y4))};
            // 另一条直线不平行于此直线
            } else {
                x = x1;
                y = (x - x4) * (y3 - y4) / (x3 - x4) + y4;
            }
        // 第一条直线平行于 Y 轴
        } else if (y1 - y2 == 0) {
            // 四个端点的对称点
            int[] newStart1     = new int[] {start1[1], start1[0]},
                    newEnd1     = new int[] {end1[1], end1[0]},
                    newStart2   = new int[] {start2[1], start2[0]},
                    newEnd2     = new int[] {end2[1], end2[0]};
            double[] tmp = intersection(newStart1, newEnd1, newStart2, newEnd2);
            return new double[] {tmp[1], tmp[0]};
        // 第二条直线平行于 X 轴
        } else if (x3 - x4 == 0)
            return intersection(start2, end2, start1, end1);
        // 第二条直线平行于 Y 轴
        else if (y3 - y4 == 0) 
            return intersection(start2, end2, start1, end1);
        // 两条直线平行,但不平行于 X 轴或 Y 轴
        else if ((y1 - y2) / (x1 - x2) == (y3 - y4) / (x3 - x4) &&
                x2 * (y2 - y1) / (x1 - x2) + y2 == x4 * (y4 - y3) / (x3 - x4) + y4) {
            x = Math.max(Math.min(x1, x2), Math.min(x3, x4));
            y = Math.max(Math.min(y1, y2), Math.min(y3, y4));
        // 普通情况
        } else {
            x = ((y4 - y2) * (x1 - x2) * (x3 - x4) + x2 * (y1 - y2) * (x3 - x4) - x4 * (y3 - y4) * (x1 - x2))
                    / ((y1 - y2) * (x3 - x4) - (y3 - y4) * (x1 - x2));
            y = (x - x2) * (y1 - y2) / (x1 - x2) + y2;
        }
        // 交点可能存在的左、右、下、上边界
        double  left    = Math.max(Math.min(x1, x2), Math.min(x3, x4)),
                right   = Math.min(Math.max(x1, x2), Math.max(x3, x4)),
                bottom  = Math.max(Math.min(y1, y2), Math.min(y3, y4)),
                top     = Math.min(Math.max(y1, y2), Math.max(y3, y4));
        if (left <= x && x <= right && bottom <= y && y <= top)
            return new double[] {x, y};
        else return new double[] {};
    }

猜你喜欢

转载自www.cnblogs.com/xym4869/p/12660356.html
今日推荐