@shawngao Thanks for the clear solution! One small improvement, we only need to track indices, instead of the actual Points. Here's the C++ version:

class Solution {
private:
vector<Point> points;
struct comp{
bool operator() (Point a, Point b) {
return a.x==b.x ? a.y<b.y : a.x<b.x;
}
};
int cross(int ai,int bi,int ci) {
int bax=points[bi].x-points[ai].x;
int bay=points[bi].y-points[ai].y;
int bcx=points[bi].x-points[ci].x;
int bcy=points[bi].y-points[ci].y;
return bax*bcy-bay*bcx;
}
int dist(int ai,int bi) {
int bax=points[bi].x-points[ai].x;
int bay=points[bi].y-points[ai].y;
return bax*bax+bay*bay;
}
public:
vector<Point> outerTrees(vector<Point>& points) {
this->points = points;
set<Point,comp> pset;
vector<Point> res;
int n=points.size(), fi=0, ni=-1;
for (int i=0; i<n; i++) if (points[i].x<points[fi].x) fi=i;
int ci=fi;
pset.insert(points[fi]);
while (ci!=fi || ni==-1) {
ni=0;
for (int i=0; i<n; i++) {
if (ci==i) continue;
if (ni==i || cross(ci,i,ni)>0 ||
(cross(ci,i,ni)==0 & dist(ci,i)>dist(ci,ni))) {
ni=i;
}
}
for (int i=0; i<n; i++) {
if (ci==i) continue;
if (cross(ci,i,ni)==0) pset.insert(points[i]);
}
ci=ni;
}
for (Point p:pset) res.push_back(p);
return res;
}
};