zoukankan      html  css  js  c++  java
  • LeetCode 面试题 16.03. 交点

    我的LeetCode:https://leetcode-cn.com/u/ituring/

    我的LeetCode刷题源码[GitHub]:https://github.com/izhoujie/Algorithmcii

    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
    著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

    解题思路

    既然是求两条__线段__是否有交点并返回交点,最直接的想法就是计算线段所在直线方程并解决就行了;

    思路1-求直线方程再分情况处理

    首先,需要明确两条线段的各自最小及最大x和y,便于后续计算判断,然后再分情况判断:
    步骤:

    • 计算各自的斜截式方程的k和b;(因为可能不存在k,k需要给一个防御值,不影响后面使用)
    • 先判断不相交的情况,即判断线段的边界情况,这里的逻辑跟LeetCode 836 矩形重叠一致;
    • 若斜率均不存在,那么x已确定,y是二者最小y中的最大者;
    • 若其中之一不存在斜率,则x已确定,根据斜截式求y并验证y是否在前者的y之间;
    • 若都存在斜率:
      - 斜率相等,则根据斜率的正负特性(增/减函数)去判断找交点即可;
      - 斜率不等,直接求交点并判断是否在线段上;
      图解:

    算法复杂度:

    • 时间复杂度: $ {color{Magenta}{Omicronleft(1 ight)}} $
    • 空间复杂度: $ {color{Magenta}{Omicronleft(1 ight)}} $

    算法源码示例

    package leetcode;
    
    /**
     * @author ZhouJie
     * @date 2020年4月12日 下午10:26:53 
     * @Description: 面试题 16.03. 交点
     *	
     */
    public class LeetCode_Offer_16_03 {
    	public double[] intersection_1(int[] start1, int[] end1, int[] start2, int[] end2) {
    		// 两线段的x和y的最值
    		int minX1 = Math.min(start1[0], end1[0]);
    		int minX2 = Math.min(start2[0], end2[0]);
    		int minY1 = Math.min(start1[1], end1[1]);
    		int minY2 = Math.min(start2[1], end2[1]);
    
    		int maxX1 = Math.max(start1[0], end1[0]);
    		int maxX2 = Math.max(start2[0], end2[0]);
    		int maxY1 = Math.max(start1[1], end1[1]);
    		int maxY2 = Math.max(start2[1], end2[1]);
    		// 对于x和y,若其中一条线段的最小值大于另一条的最大值,则它们必不相交
    		if (minX1 > maxX2 || minX2 > maxX1 || minY1 > maxY2 || minY2 > maxY1) {
    			return new double[0];
    		}
    		// 若均不存在斜率,那么x值已确定,y只需要取二者最小中的最大值即可
    		if (minX1 == maxX1 && minX2 == maxX2 && minX1 == maxX2) {
    			return new double[] { minX1, Math.max(minY1, minY2) };
    		}
    		// 计算y=kx+b的斜率k和截距b 以防斜率不存在计算k时使用三目运算给防御值0
    		double k1 = minX1 == maxX1 ? 0 : (start1[1] - end1[1]) * 1.0 / (start1[0] - end1[0]);
    		double k2 = minX2 == maxX2 ? 0 : (start2[1] - end2[1]) * 1.0 / (start2[0] - end2[0]);
    		double b1 = start1[1] - k1 * start1[0];
    		double b2 = start2[1] - k2 * start2[0];
    		// 若其中之一无斜率,则x可确定,直接求y值,并判断y是否在无斜率的y区间内即可
    		if (minX1 == maxX1) {
    			double y = k2 * minX1 + b2;
    			if (y >= minY1 && y <= maxY1) {
    				return new double[] { minX1, y };
    			} else {
    				return new double[0];
    			}
    		} else if (minX2 == maxX2) {
    			double y = k1 * minX2 + b1;
    			if (y >= minY2 && y <= maxY2) {
    				return new double[] { minX2, y };
    			} else {
    				return new double[0];
    			}
    		} else if (k1 == k2) {
    			// 若斜率相等,则b不等时必不想交,b相等时需要再分别判断重叠部分的情况
    			if (b1 != b2) {
    				return new double[0];
    				// 根据斜率的正负很容易判断左侧交点的情况
    			} else if (k1 > 0) {
    				if (minX1 > minX2) {
    					return new double[] { minX1, minY1 };
    				} else {
    					return new double[] { minX2, minY2 };
    				}
    			} else {
    				if (minX1 > minX2) {
    					return new double[] { minX1, maxY1 };
    				} else {
    					return new double[] { minX2, maxX2 };
    				}
    			}
    		} else {
    			// 斜率都存在且不等,直接求节点并判断区间即可
    			double x = (b2 - b1) / (k1 - k2);
    			double y = k1 * x + b1;
    
    			boolean f1 = x >= minX1 && x <= maxX1 && x >= minX2 && x <= maxX2;
    			boolean f2 = y >= minY1 && y <= maxY1 && y >= minY2 && y <= maxY2;
    
    			if (f1 && f2) {
    				return new double[] { x, y };
    			} else {
    				return new double[0];
    			}
    		}
    	}
    }
    
  • 相关阅读:
    2020.7.23第十八天
    2020.7.22第十七天
    本周总结
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
  • 原文地址:https://www.cnblogs.com/izhoujie/p/12707111.html
Copyright © 2011-2022 走看看