You are tasked with fencing a garden containing various trees using the minimum length of rope possible. Given an array trees where trees[i] = [xi, yi] represents the location of a tree in the garden, you need to find the convex hull - the smallest perimeter that encloses all trees.
The fence should form a convex polygon that contains or touches every tree. Trees that lie exactly on the fence perimeter are part of the solution.
Goal: Return the coordinates of all trees that are located exactly on the fence perimeter.
Input: Array of 2D coordinates representing tree positions
Output: Array of coordinates that form the convex hull boundary
Note: You may return the coordinates in any order.
The optimal solution uses Graham's Scan algorithm which sorts points by polar angle and uses a stack to build the convex hull in O(n log n) time. The key insight is using cross products to determine if three consecutive points make a left turn (convex) or right turn (concave), allowing us to eliminate interior points efficiently.
Common Approaches
✓
Brute Force (Check All Combinations)
⏱️ Time: O(2^n * n^3)
Space: O(n)
For every possible combination of points, check if they form a convex polygon that contains all other points. This involves checking all subsets and validating each one.
Graham Scan Algorithm
⏱️ Time: O(n log n)
Space: O(n)
Graham's scan algorithm uses sorting and a stack-based approach to build the convex hull. We start from the bottommost point and sort all other points by polar angle, then use a stack to maintain the convex hull.
Brute Force (Check All Combinations) — Algorithm Steps
Generate all possible subsets of points (2^n subsets)
For each subset, check if points form a convex polygon
Verify that all remaining points are inside or on the polygon boundary
Return the minimal valid subset that encloses all points
Visualization
Tap to expand
Step-by-Step Walkthrough
1
Generate Combinations
Try all possible subsets of 3, 4, 5... points as potential hull candidates
2
Check Convexity
For each candidate, verify that it forms a convex polygon using cross products
3
Verify Containment
Ensure all remaining points are inside or on the boundary of the candidate hull
4
Return First Valid
Return the first valid hull found (starting with smallest possible size)
Code -
solution.c — C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
int x, y;
} Point;
long long cross(Point O, Point A, Point B) {
return (long long)(A.x - O.x) * (B.y - O.y) - (long long)(A.y - O.y) * (B.x - O.x);
}
long long distance(Point p1, Point p2) {
long long dx = p1.x - p2.x;
long long dy = p1.y - p2.y;
return dx * dx + dy * dy;
}
int comparePoints(const void* a, const void* b, void* start_ptr) {
Point p1 = *(Point*)a;
Point p2 = *(Point*)b;
Point start = *(Point*)start_ptr;
if (p1.x == start.x && p1.y == start.y) return -1;
if (p2.x == start.x && p2.y == start.y) return 1;
long long crossProd = cross(start, p1, p2);
if (crossProd == 0) {
return (distance(start, p1) < distance(start, p2)) ? -1 : 1;
}
return (crossProd > 0) ? -1 : 1;
}
static Point global_start;
int cmp(const void* a, const void* b) {
return comparePoints(a, b, &global_start);
}
Point* outerTrees(Point* trees, int n, int* returnSize) {
*returnSize = 0;
if (n <= 1) {
Point* result = (Point*)malloc(n * sizeof(Point));
for (int i = 0; i < n; i++) {
result[i] = trees[i];
}
*returnSize = n;
return result;
}
// Find the bottom-most point (and left-most in case of tie)
Point start = trees[0];
for (int i = 1; i < n; i++) {
if (trees[i].y < start.y || (trees[i].y == start.y && trees[i].x < start.x)) {
start = trees[i];
}
}
global_start = start;
qsort(trees, n, sizeof(Point), cmp);
// Find collinear points at the end and reverse them
int i = n - 1;
while (i > 0 && cross(start, trees[i], trees[n - 1]) == 0) {
i--;
}
// Reverse from i+1 to n-1
for (int left = i + 1, right = n - 1; left < right; left++, right--) {
Point temp = trees[left];
trees[left] = trees[right];
trees[right] = temp;
}
// Graham scan
Point* hull = (Point*)malloc(n * sizeof(Point));
int hullSize = 0;
for (int j = 0; j < n; j++) {
while (hullSize >= 2 && cross(hull[hullSize - 2], hull[hullSize - 1], trees[j]) < 0) {
hullSize--;
}
hull[hullSize++] = trees[j];
}
*returnSize = hullSize;
return hull;
}
int main() {
char input[10000];
fgets(input, sizeof(input), stdin);
// Parse input
Point trees[1000];
int n = 0;
char* ptr = input + 1; // Skip first '['
while (*ptr && *ptr != ']') {
if (*ptr == '[') {
ptr++;
trees[n].x = strtol(ptr, &ptr, 10);
ptr++; // Skip comma
trees[n].y = strtol(ptr, &ptr, 10);
n++;
ptr++; // Skip ']'
} else {
ptr++;
}
}
int returnSize;
Point* result = outerTrees(trees, n, &returnSize);
printf("[");
for (int i = 0; i < returnSize; i++) {
if (i > 0) printf(",");
printf("[%d,%d]", result[i].x, result[i].y);
}
printf("]\n");
free(result);
return 0;
}
Time & Space Complexity
Time Complexity
⏱️
O(2^n * n^3)
2^n subsets to check, each requiring O(n^3) operations for convexity and containment checks
n
2n
⚠ Quadratic Growth
Space Complexity
O(n)
Space to store the current subset being evaluated
n
2n
⚡ Linearithmic Space
24.5K Views
MediumFrequency
~25 minAvg. Time
892 Likes
Ln 1, Col 1
Smart Actions
💡Explanation
AI Ready
💡 SuggestionTabto acceptEscto dismiss
// Output will appear here after running code
Code Editor Closed
Click the red button to reopen
Algorithm Visualization
Pinch to zoom • Tap outside to close
Test Cases
0 passed
0 failed
3 pending
Select Compiler
Choose a programming language
Compiler list would appear here...
AI Editor Features
Header Buttons
💡
Explain
Get a detailed explanation of your code. Select specific code or analyze the entire file. Understand algorithms, logic flow, and complexity.
🔧
Fix
Automatically detect and fix issues in your code. Finds bugs, syntax errors, and common mistakes. Shows you what was fixed.
💡
Suggest
Get improvement suggestions for your code. Best practices, performance tips, and code quality recommendations.
💬
Ask AI
Open an AI chat assistant to ask any coding questions. Have a conversation about your code, get help with debugging, or learn new concepts.
Smart Actions (Slash Commands)
🔧
/fix Enter
Find and fix issues in your code. Detects common problems and applies automatic fixes.
💡
/explain Enter
Get a detailed explanation of what your code does, including time/space complexity analysis.
🧪
/tests Enter
Automatically generate unit tests for your code. Creates comprehensive test cases.
📝
/docs Enter
Generate documentation for your code. Creates docstrings, JSDoc comments, and type hints.
⚡
/optimize Enter
Get performance optimization suggestions. Improve speed and reduce memory usage.
AI Code Completion (Copilot-style)
👻
Ghost Text Suggestions
As you type, AI suggests code completions shown in gray text. Works with keywords like def, for, if, etc.
Tabto acceptEscto dismiss
💬
Comment-to-Code
Write a comment describing what you want, and AI generates the code. Try: # two sum, # binary search, # fibonacci
💡
Pro Tip: Select specific code before using Explain, Fix, or Smart Actions to analyze only that portion. Otherwise, the entire file will be analyzed.