一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情。
| 有帮助的话请点个赞吧~ |
刷题的时候看到了新的概念,来好好学习一下。
定义
-
在一个实数向量空间中,对于给定集合,所有包含的凸集的交集被称为的凸包。
- 凸集:在点集拓扑学与欧几里得空间中,凸集(Convex set)是一个点集合,其中每两点之间的直线点都落在该点集合中。
- 其实可以发现这些点集构成的图形每个边都是向外凸的,所以才叫凸集嘛。
- 的凸包可以用内所有点的线性组合来构造。
-
在二维欧几里得空间中,凸包可想象为一条刚好包着所有点的橡皮圈。
算法简介
- 增量式算法
- 逐个将点加入集合构成凸包,检查之前的点是否存在于新的凸包集合。
- 每次都要检查之前所有的点,遍历套一个遍历,所以时间复杂度为
- 包裹法(Jarvis步进法)
- 由必定在凸包的点开始,如最左边的点,然后找右边的第一个点,使得其他所有点与构成的向量都在向量右边。(比较所有向量的极坐标角度)
- 然后以作为向量起点,重复上述步骤,依次找到后续的,最终会找回到起点。
- 总共会找到个点,每找一个点的时间复杂度为,所以总时间复杂度为。
- 会每次都重复遍历后面所有的点。
- 葛立恒(Graham)扫描法
- 由最底的点开始(最左下),计算它与其他各点连线与x轴正向的角度,由小到大排序,称其对应点为。
- 从该集合中依次取点判断,上一条路径到下一条路径是向右(内)转还是向左(外)转
- 若向右转则该点不会在凸包上,丢弃考虑下一个点;
- 若向左转则以该点为头重复判断,直至最终转回。
- 如最开始考虑路径相对路径如何变化:
- 若向右(内),则表示不可能是凸包上的一点,开始判断;
- 若向左(外):则表示可能是凸包上的一点,开始判断。
- 时间复杂度由前面的排序决定,后面判断为,则整体时间复杂度为。
- 每个点只会被考虑一次,但不可推广到二维以上的情况。
- 单调链(Andrew算法基于此)
- 按坐标进行双关键字排序,先按x坐标值排序,再按y坐标值排序。(从左到右、从下到上)
- 选择x坐标为最小值的点,在这些点中找出y坐标的值最大和y坐标的值最小的点。对于x坐标为最大值也是这样处理。将两组点中y坐标值较小的点连起。在这条线段下的点,找出它们之中y坐标值最大的点,又在它们之间找x坐标值再最小和最大的点……如此类推。
- 大概是先定位首尾边界,然后找离连线最近的凸包外点,分别与边界相连,再继续找离新连线最近的外点……一个一个往里面放。
- 分治链
- 将点集划分为两个不相交的子集,分别求两者的凸包后,计算这两个凸包的凸包,结果即为的凸包。(二分)
- 时间复杂度为
- 快包法(Akl-Toussaint启发式)
- 选择最左、最右、最上、最下的点构成一个凸四边形,排除其内的点,然后其余点按靠近的边划分为四个部分,再分别进行快包法(Quick Hull)。
实现应用
在leetcode587.安装栅栏一题中进行更详细的叙述与应用,并用两种语言实现了三种算法,可以康康这里→ Java&C++题解与拓展——leetcode587.安装栅栏【二维凸包学习】。
参考
[1] 凸包 - wikipedia
| 欢迎指正与讨论! |