Erect the Fence

hard geometry convex hull

Problem

Given tree coordinates, return the points lying on the convex hull (the perimeter of the rope around all trees, including collinear ones).

Inputtrees=[[1,1],[2,2],[2,0],[2,4],[3,3],[4,2]]
Output[[1,1],[2,0],[4,2],[3,3],[2,4]]
Convex hull vertices.

def outer_trees(trees):
    trees.sort()
    def cross(o, a, b): return (a[0]-o[0])*(b[1]-o[1]) - (a[1]-o[1])*(b[0]-o[0])
    lower, upper = [], []
    for p in trees:
        while len(lower) >= 2 and cross(lower[-2], lower[-1], p) < 0: lower.pop()
        lower.append(p)
    for p in reversed(trees):
        while len(upper) >= 2 and cross(upper[-2], upper[-1], p) < 0: upper.pop()
        upper.append(p)
    return list({tuple(p) for p in lower + upper})
function outerTrees(trees) {
  trees.sort((a, b) => a[0]-b[0] || a[1]-b[1]);
  const cross = (o, a, b) => (a[0]-o[0])*(b[1]-o[1]) - (a[1]-o[1])*(b[0]-o[0]);
  const lower = [], upper = [];
  for (const p of trees) {
    while (lower.length >= 2 && cross(lower[lower.length-2], lower[lower.length-1], p) < 0) lower.pop();
    lower.push(p);
  }
  for (let i = trees.length - 1; i >= 0; i--) {
    const p = trees[i];
    while (upper.length >= 2 && cross(upper[upper.length-2], upper[upper.length-1], p) < 0) upper.pop();
    upper.push(p);
  }
  return [...new Set([...lower, ...upper].map(p => p.join(',')))].map(s => s.split(',').map(Number));
}
int[][] outerTrees(int[][] trees) {
    Arrays.sort(trees, (a, b) -> a[0] != b[0] ? a[0]-b[0] : a[1]-b[1]);
    Deque lower = new ArrayDeque<>(), upper = new ArrayDeque<>();
    for (int[] p : trees) {
        while (lower.size() >= 2 && cross(secondLast(lower), lower.peek(), p) < 0) lower.pop();
        lower.push(p);
    }
    for (int i = trees.length - 1; i >= 0; i--) {
        int[] p = trees[i];
        while (upper.size() >= 2 && cross(secondLast(upper), upper.peek(), p) < 0) upper.pop();
        upper.push(p);
    }
    Set seen = new HashSet<>();
    List out = new ArrayList<>();
    for (int[] p : lower) if (seen.add(p[0]+","+p[1])) out.add(p);
    for (int[] p : upper) if (seen.add(p[0]+","+p[1])) out.add(p);
    return out.toArray(new int[0][]);
}
int cross(vector& o, vector& a, vector& b) {
    return (a[0]-o[0])*(b[1]-o[1]) - (a[1]-o[1])*(b[0]-o[0]);
}
vector> outerTrees(vector>& trees) {
    sort(trees.begin(), trees.end());
    vector> lo, up;
    for (auto& p : trees) {
        while (lo.size() >= 2 && cross(lo[lo.size()-2], lo.back(), p) < 0) lo.pop_back();
        lo.push_back(p);
    }
    for (int i = trees.size()-1; i >= 0; i--) {
        auto& p = trees[i];
        while (up.size() >= 2 && cross(up[up.size()-2], up.back(), p) < 0) up.pop_back();
        up.push_back(p);
    }
    set> s(lo.begin(), lo.end()); s.insert(up.begin(), up.end());
    return {s.begin(), s.end()};
}
Time: O(n log n) Space: O(n)