Purpose: Compute the convex hull of a set of 2D points, in O(N log N) time, by building the upper and lower hulls separately after sorting by coordinates.
Algorithm
- Sort all points lexicographically (by x-coordinate, breaking ties by y-coordinate).
- Build the lower hull: process points left to right, maintaining a stack; while the last three points make a clockwise or straight turn, pop the middle one, then push the current point.
- Build the upper hull: process points right to left using the same turn-popping rule.
- Concatenate the lower and upper hulls (removing the duplicate endpoints shared between them) to get the full convex hull in counter-clockwise order.
Code
struct Point { long long x, y; bool operator<(const Point& o) const { return x < o.x || (x == o.x && y < o.y); } };
long long cross(Point O, Point A, Point B) {
return (A.x - O.x) * (B.y - O.y) - (A.y - O.y) * (B.x - O.x);
}
vector<Point> monotoneChain(vector<Point> pts) {
int n = pts.size();
if (n < 3) return pts;
sort(pts.begin(), pts.end());
vector<Point> hull(2 * n);
int k = 0;
for (int i = 0; i < n; i++) {
while (k >= 2 && cross(hull[k-2], hull[k-1], pts[i]) <= 0) k--;
hull[k++] = pts[i];
}
int lowerSize = k + 1;
for (int i = n - 2; i >= 0; i--) {
while (k >= lowerSize && cross(hull[k-2], hull[k-1], pts[i]) <= 0) k--;
hull[k++] = pts[i];
}
hull.resize(k - 1);
return hull;
}Paradigm
Greedy (with a Transform-and-Conquer sort step). After sorting points by x-coordinate (a preprocessing transform), each of the two scanning passes greedily keeps a point only while it maintains a consistent turn direction, permanently discarding points that create a concave turn.
Complexity
- Time: O(N log N), dominated by the coordinate sort
- Space: O(N)
Proof of Correctness
Why building lower and upper hulls separately covers the full hull: Every point on the convex hull lies either on the βlowerβ boundary (the chain of points with no point below the segment connecting hull neighbors) or the βupperβ boundary, when points are ordered by x-coordinate. The leftmost and rightmost points are shared between both chains, so building each independently and concatenating (minus duplicate shared endpoints) reconstructs the complete hull.
Why the turn-popping scan correctly builds each chain: This mirrors the same invariant argument as Graham Scan: processing points in sorted (x-coordinate) order and popping the stack whenever the last three points form a clockwise or collinear turn maintains the invariant that the stack always represents the correct partial lower (or upper) hull of the points processed so far. A popped point is provably not part of the hull chain at this stage, since its presence would create a concave dent β any point causing this can always be shown to lie strictly below (for lower hull) the segment connecting its stack-neighbors, hence redundant.
Why sorting by x (not polar angle) still works: Unlike Graham Scan, no pivot or angular sort is needed because scanning left-to-right and right-to-left directly traces the lower and upper boundaries in a well-defined monotonic order β x-coordinate order guarantees each point is processed exactly once per pass in a consistent geometric direction, avoiding the angular-comparison edge cases (e.g., points with equal angles) that Graham Scan must handle explicitly.
Termination and correctness: After both passes, the stack holds every hull vertex exactly once (each chain contributes its unique vertices, with the two shared endpoints deduplicated), giving the correct convex hull. β
Variants / Use Cases
- Graham Scan β alternative approach using pivot + polar-angle sort instead of x-coordinate sort
- Numerically robust hull construction β monotone chain is often preferred in practice since x-coordinate sorting avoids some polar-angle floating-point pitfalls
- Convex hull trick (CHT) for DP optimization β builds a related monotone structure (upper/lower envelope of lines) using similar turn-based logic
- Collision detection / bounding shapes β same downstream uses as any convex hull algorithm
- Half-plane intersection preprocessing β sorted, monotone-chain-style scans appear in more advanced computational geometry algorithms