传统解法

题目来自 leetcode 335. Self Crossing

题意非常简单,有一个点,一开始位于 (0, 0) 位置,然后有规律地往上,左,下,右方向移动一定的距离,判断是否会相交(self crossing)。

一个很容易想到的方案就是求出所有线段,然后用 O(n^2) 的时间复杂度两两判断线段是否相交,而线段相交的判断,可以列个二元一次方程求解(交点)。这个解法非常容易想到,但是实际操作起来比较复杂,接下去介绍利用向量的解法。

向量解法

简单回顾下向量,具体的自行谷歌。向量就是一条有向线段,这里要用到的是向量的 叉乘。(还有个类似的概念叫做 点积)

叉乘公式:

而因为 p1 X p2 = | a | * | b | * sin α,后者又是平行四边形的面积公式,所以可以用叉乘来求解平行四边形的面积(同理可以求解三角形的面积)。PS:如果给出三个点坐标,求解三角形面积的话,最好用叉乘来做,这样更精确,而不是海伦公式。

向量叉乘还能判断 p0p1 和 p0p2 两个向量, 对于 p0 点而言,p0p1 是位于 p0p2 顺时针方向,还是逆时针方向。

我们回到判断线段相交,两线段相交有如下两种可能。

对于第一种情况,我们可以判断 p1, p2 两点分别位于线段 p3p4 两边,同时满足 p3, p4 两点分别位于线段 p1p2 两边。如何判断?以判断 p1,p2 是否位于线段 p3p4 两边为例,求解叉乘 p3p1 X p3p4,以及 p3p2 X p3p4,如果符合条件,两值必是一正一负。对于第二种情况,因为共线,所以叉乘结果为 0,但是叉乘结果为 0 只能保证共线,并不能保证相交,所以还需要进行如下的判断。

这样解法就呼之欲出了,贡献个判断线段相交的模板:

/**
 * @param {object} a
 * @param {object} b
 * @return {boolean}
 * a, b 表示两条线段。
 * (a.x1, a.y1), (a.x2, a.y2) 分别表示线段 a 两个端点; b 类似
 */

function f(a, b) {

  function online(a, b, c) {
    if (a.x >= Math.min(b.x, c.x) && a.x <= Math.max(b.x, c.x) && a.y >= Math.min(b.y, c.y) && a.y <= Math.max(b.y, c.y))
      return true;

    return false;
  }

  var n1, n2, n3, n4;

  n1 = (a.x1 - b.x2) * (b.y1 - b.y2) - (a.y1 - b.y2) * (b.x1 - b.x2);
  n2 = (a.x2 - b.x2) * (b.y1 - b.y2) - (a.y2 - b.y2) * (b.x1 - b.x2);
  n3 = (b.x1 - a.x2) * (a.y1 - a.y2) - (b.y1 - a.y2) * (a.x1 - a.x2);
  n4 = (b.x2 - a.x2) * (a.y1 - a.y2) - (b.y2 - a.y2) * (a.x1 - a.x2);

  if (n1 * n2 < 0 && n3 * n4 < 0)
    return 1;

  var p1 = {x: a.x1, y: a.y1};

  var p2 = {x: a.x2, y: a.y2};

  var p3 = {x: b.x1, y: b.y1};

  var p4 = {x: b.x2, y: b.y2};

  if (n1 === 0 && online(p1, p3, p4))
    return 1;

  if (n2 === 0 && online(p2, p3, p4))
    return 1;

  if (n3 === 0 && online(p3, p1, p2))
    return 1;

  if (n4 === 0 && online(p4, p1, p2))
    return 1;

  return 0;
}

本题完整代码详见 https://github.com/hanzichi/leetcode/tree/master/Algorithms/Self%20Crossing,求 star, 求 fork,求 follow

还记得高中的向量吗?leetcode 335. Self Crossing(判断线段相交)的更多相关文章

  1. [leetcode]335. Self Crossing

    You are given an array x of n positive numbers. You start at point (,) and moves x[] metres to the n ...

  2. nyoj-1016-德莱联盟(向量叉乘判断线段相交)

    叉乘的坐标表示: A(X1,Y1), B(X2, Y2), C(XC,YC), D(XD, YD);AB = (X2-X1, Y2-Y1);CD = (XD-XC, YD-YC); 向量AB,CD的叉 ...

  3. c#静态构造函数 与 构造函数 你是否还记得?

    构造函数这个概念,在我们刚开始学习编程语言的时候,就被老师一遍一遍的教着.亲,现在你还记得静态构造函数的适用场景吗?如果没有,那么我们一起来复习一下吧. 静态构造函数是在构造函数方法前面添加了stat ...

  4. 《C#编程风格》还记得多少

    开始实习之后,才发现自己是多么地菜.还有好多东西还要去学习. 公司很好,还可以帮你买书.有一天随口问了一下上司D,代码规范上面有什么要求.然后D在Amazon上面找到了这本书<C#编程风格(Th ...

  5. 【编程之外】还记得曾经给'大学导师'写过的报告嘛 --> 前方高能

    写在前面 本文不是讲技术的,也没什么代码可看 本文不是讲技术的,也没什么代码可看 本文不是讲技术的,也没什么代码可看 还记得我们曾经给我们大学''导师''写过的报告嘛? 大学他愿意在凌晨6点向你询问近 ...

  6. c#静态构造函数 与 构造函数 你是否还记得?(转载)

    构造函数这个概念,在我们刚开始学习编程语言的时候,就被老师一遍一遍的教着.亲,现在你还记得静态构造函数的适用场景吗?如果没有,那么我们一起来复习一下吧.静态构造函数是在构造函数方法前面添加了stati ...

  7. 你还记得当初为什么进入IT行业吗?

    说到这个问题,小编相信不少童鞋开始忆往昔峥嵘岁月,那个少年为了心中的改变世界的理想,进入了这个行业,但是呢,有一群人画风就不一样了,他们进入IT行业,完全只是是因为.... 小时候广告看多了....: ...

  8. 使用Code First建模自引用关系笔记 asp.net core上使用redis探索(1) asp.net mvc控制器激活全分析 语言入门必学的基础知识你还记得么? 反射

    使用Code First建模自引用关系笔记   原文链接 一.Has方法: A.HasRequired(a => a.B); HasOptional:前者包含后者一个实例或者为null HasR ...

  9. .NET成人礼 | 还记得20年前一起拖过的控件吗?

    本文是MVP Ediwang写的回忆一个80后的拖控件的感悟,与君共勉: 每一代人都有记忆里的味道.煤球炉.黑白电视机是属于父母的记忆.而“拖控件”式编程,启蒙了无数像我这样的80后(嗯,89也算80 ...

随机推荐

  1. 如何分析解读systemstat dump产生的trc文件

    ORACLE数据库的systemstat dump生成trace文件虽然比较简单,但是怎么从trace文件中浩如烟海的信息中提炼有用信息,并作出分析诊断是一件技术活,下面收集.整理如何分析解读syst ...

  2. C#语言——类

    C#——类 一.String 类 系统内置的处理字符串类型的函数方法类.方便我们对字符串类型进行一系列的处理. 1.Length:获取字符串的长度,返回一个int类型的值 string x=Conso ...

  3. linux文件分发脚本

    1.说明 此脚本可分发两类文件,1.固定内容文件,2.(每台被分发主机)内容不同的文件 ppp.sh为拨号脚本,每台被分发主机内容不同 根据分发文件名字不同(ppp.sh和其他文件)自动选择分发方式 ...

  4. 烂泥:ESXI开启SNMP服务

    本文由秀依林枫提供友情赞助,首发于烂泥行天下. 要监控ESXI,打算通过snmp方式进行监控,这样操作比较简单.但是要使用SNMP方式进行监控,必须要开启ESXI的SNMP服务.ESXI由于版本号的不 ...

  5. sed入门详解教程

    sed是一个比较古老的,功能十分强大的用于文本处理的流编辑器,加上正则表达式的支持,可以进行大量的复杂的文本编辑操作.sed本身是一个非常复杂的工具,有专门的书籍讲解sed的具体用法,但是个人觉得没有 ...

  6. 高性能MySQL笔记 第5章 创建高性能的索引

    索引(index),在MySQL中也被叫做键(key),是存储引擎用于快速找到记录的一种数据结构.索引优化是对查询性能优化最有效的手段.   5.1 索引基础   索引的类型   索引是在存储引擎层而 ...

  7. 四、Android学习第四天——JAVA基础回顾(转)

    (转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 四.Android学习第四天——JAVA基础回顾 这才学习Android的 ...

  8. 树莓派2 安装 win10Iot 和 Ubuntu mate

    注册博客账号已经2年多了.一直没写博文现在抽空写写. 写这篇博文是因为我之前在网上找了蛮多有关教程写的都不是很清晰.安装没成功.所以我写一下我根据网上找到的整理一下分享出来. 非专业只是业余玩玩.好了 ...

  9. C#学习笔记-icon托盘图标的简单知识

    在做整个类似QQ的毕业设计中,有一个小图标把我给难了一阵子,就是托盘小图标

  10. openjudge1768 最大子矩阵[二维前缀和or递推|DP]

    总时间限制:  1000ms 内存限制:  65536kB 描述 已知矩阵的大小定义为矩阵中所有元素的和.给定一个矩阵,你的任务是找到最大的非空(大小至少是1 * 1)子矩阵. 比如,如下4 * 4的 ...