content: public 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 boolean inBetween(int[] p, int[] i, int[] q) {
          boolean a = i[0] >= p[0] && i[0] <= q[0] || i[0] <= p[0] && i[0] >= q[0];
          boolean b = i[1] >= p[1] && i[1] <= q[1] || i[1] <= p[1] && i[1] >= q[1];
          return a && b;
      }
  
      public int[][] outerTrees(int[][] points) {
          HashSet<int[]> hull = new HashSet<> ();
          if (points.length < 4) {
              for (int[] p: points)
                  hull.add(p);
              return hull.toArray(new int[hull.size()][]);
          }
          int left_most = 0;
          for (int i = 0; i < points.length; i++)
              if (points[i][0] < points[left_most][0])
                  left_most = i;
          int p = left_most;
          do {
              int q = (p + 1) % points.length;
              for (int i = 0; i < points.length; i++) {
                  if (hull.contains(points[i]))
                      continue;  
                  
                  if (orientation(points[p], points[i], points[q]) < 0) {
                      q = i;
                  }
              }
              for (int i = 0; i < points.length; i++) {
                  if (i != p && i != q && orientation(points[p], points[i], points[q]) == 0 && inBetween(points[p], points[i], points[q])) {
                      hull.add(points[i]);
                  }
              }
              hull.add(points[q]);
              p = q;
          }
          while (p != left_most);
          return hull.toArray(new int[hull.size()][]);
      }
  }