题目链接:安装栅栏
题解标签:凸包
思路:
经典凸包题
对所有点按X坐标从小到大排序,如果X坐标相同,则按Y坐标从小到大排序。
使用栈记录形成凸包的点集。
算法动图如下:
算法流程如下:
1、以第一个点为基点,从前往后遍历。
2、当栈中点数小于2时,入栈。
3、当栈中点数大于等于2时,判断当前点(C)和栈顶两点(A、B)形成的线段AB和BC夹角是否大于180°。①如果大于,则栈顶出栈,重复步骤2、3,②否则当前点入栈。
4、遍历至最后一个点后,反方向相同逻辑重新遍历直至第一个点。
5、栈内点去重则得到形成凸包的所有点。
算法复杂度:排序O(nlogn) + 遍历O(n) = O(nlogn)
代码:
class Solution {
public int orientation(int[] p, int[] q, int[] r) {
return (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
}
public int[][] outerTrees(int[][] points) {
Arrays.sort(points, (p, q) -> q[0] - p[0] == 0 ? q[1] - p[1] : q[0] - p[0]);
Stack<int[]> hull = new Stack<>();
for (int[] point : points) {
while (hull.size() >= 2 && orientation(hull.get(hull.size() - 2), hull.get(hull.size() - 1), point) > 0)
hull.pop();
hull.push(point);
}
hull.pop();
for (int i = points.length - 1; i >= 0; i--) {
while (hull.size() >= 2 && orientation(hull.get(hull.size() - 2), hull.get(hull.size() - 1), points[i]) > 0)
hull.pop();
hull.push(points[i]);
}
HashSet<int[]> set = new HashSet<>(hull);
return set.toArray(new int[set.size()][2]);
}
}