传统解法

题目来自 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. 用Phaser实现Flappy Bird 游戏

    How to Make a Flappy Bird in HTML5 With Phaser - Part 1 Flappy Bird is a nice little game with easy ...

  2. eclipse常用配置

    一. 手动方式安装svn插件 1. 根据本地的svn客户端的版本,到http://subclipse.tigris.org/ 下载eclipse对应版本的svn插件包 注:装eclipse里面的svn ...

  3. Linux 多线程编程

    概念 原来指向main()的线程叫做主线程(main thread) 使用pthread_create()创建出来的线程,叫做子线程(child thread) 主/子线程只有在创建时才有区别, 创建 ...

  4. 字典dictionary

    字典,即我们可以通过索引来查找更详细的内容.每个item都是由一对index:value构成的 索引可以有副本,但是试图根据存在副本的索引访问元素时,只会取最靠后的那个. 索引必须是immutable ...

  5. 绕过校园网的共享限制 win10搭建VPN服务器实现--从入门到放弃

    一.开篇立论= =.. 上次说到博主在电脑上搭建了代理服务器来绕过天翼客户端的共享限制,然而经过实际测试还不够完美,所以本着生命不息,折腾不止的精神,我又开始研究搭建vpn服务器= =... (上次的 ...

  6. 基于JAVA的全国天气预报接口调用示例

    step1:选择本文所示例的接口"全国天气预报接口" url:https://www.juhe.cn/docs/api/id/39/aid/87step2:每个接口都需要传入一个参 ...

  7. Google Cloud Platform

    一个离我们很遥远,很遥远的公司.作为全球三大公有云厂商之一,在国内根本听不到他的声音.其实吧,听到了也没用,因为在国内没法用!AWS还在纠结的落地过程中挣扎,GCP基本上就当不存在吧. 抛开这些乌烟瘴 ...

  8. Android开发中上线后修改应用名称的若干问题

    一.在Android Studio 1.3中修改app的包名: 需求来源: 之前开发的app已经在腾讯的应用宝上线,应客户要求,app需要改名字,这个就有点麻烦了.如果申请改名字,要求如下: 截图上图 ...

  9. UIScrollView 滑动复位

    需求 在每次打开界面滑动列表都是复位状态(未滑动). 分析 在制作滑动列表时常常会结合UIPanel和UIScrollView 要让滑动列表回到未滑动时的位置,那么就需要改变Panel的Clippin ...

  10. SQL存储过程、视图

    存储过程: 存储过程(stored procedure)有时也称为sproc.存储过程存储于数据库中而不是在单独的文件中,有输入参数.输出参数以及返回值等. 在数据库中,创建存储过程和创建其他对象的过 ...