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.
๐ก Note:The fence forms a pentagon that encloses all trees. The points [1,1], [2,0], [4,2], [3,3], and [2,4] form the convex hull boundary.
example_2.py โ Collinear Points
$Input:trees = [[1,2],[2,2],[4,2]]
โบOutput:[[4,2],[2,2],[1,2]]
๐ก Note:All three points lie on the same horizontal line, so they all must be included in the fence perimeter since they form the convex hull.
example_3.py โ Single Point
$Input:trees = [[0,0]]
โบOutput:[[0,0]]
๐ก Note:With only one tree, the fence is just that single point - trivial convex hull case.
Constraints
1 โค trees.length โค 3000
trees[i].length == 2
0 โค xi, yi โค 100
All the given positions are unique.
Visualization
Tap to expand
Understanding the Visualization
1
Identify Start Point
Find the bottom-most point (lowest y-coordinate, leftmost if tie) as our anchor point
2
Sort by Polar Angle
Sort all other points by the angle they make with the start point, creating a radial sweep
3
Graham Scan
Process points in order, using a stack to maintain only the convex boundary points
4
Handle Collinear Points
Include all points that lie exactly on the boundary edges of the convex hull
Key Takeaway
๐ฏ Key Insight: The convex hull is like a rubber band stretched around all points - Graham's scan efficiently finds this boundary using polar angle sorting and cross products to detect turns.
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
Approach
Time
Space
Notes
โ
Brute Force (Check All Combinations)
O(2^n * n^3)
O(n)
Check every possible subset of points to see if they form a valid convex hull
Graham Scan Algorithm
O(n log n)
O(n)
Sort points by angle, then use stack to maintain convex hull with two-pointer technique
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 <stdbool.h>
typedef struct {
int x, y;
} Point;
long long crossProduct(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);
}
bool isInsideOrOn(Point point, Point* hull, int hullSize) {
for (int i = 0; i < hullSize; i++) {
int j = (i + 1) % hullSize;
if (crossProduct(hull[i], hull[j], point) < 0) {
return false;
}
}
return true;
}
bool isConvex(Point* points, int n) {
if (n < 3) return true;
int sign = 0;
for (int i = 0; i < n; i++) {
long long cp = crossProduct(points[i], points[(i+1)%n], points[(i+2)%n]);
if (cp != 0) {
int currentSign = (cp > 0) ? 1 : -1;
if (sign == 0) {
sign = currentSign;
} else if (sign != currentSign) {
return false;
}
}
}
return true;
}
bool isValidHull(Point* trees, int n, Point* hull, int hullSize, int* selected) {
bool inHull[n];
for (int i = 0; i < n; i++) inHull[i] = false;
for (int i = 0; i < hullSize; i++) inHull[selected[i]] = true;
for (int i = 0; i < n; i++) {
if (!inHull[i]) {
if (!isInsideOrOn(trees[i], hull, hullSize)) {
return false;
}
}
}
return isConvex(hull, hullSize);
}
int** outerTrees(int** trees, int treesSize, int* treesColSize, int* returnSize, int** returnColumnSizes) {
*returnSize = treesSize;
*returnColumnSizes = malloc(treesSize * sizeof(int));
int** result = malloc(treesSize * sizeof(int*));
for (int i = 0; i < treesSize; i++) {
(*returnColumnSizes)[i] = 2;
result[i] = malloc(2 * sizeof(int));
result[i][0] = trees[i][0];
result[i][1] = trees[i][1];
}
return result;
}
int main() {
// Example usage
int trees[][2] = {{1,1},{2,2},{2,0},{2,4},{3,3},{4,2}};
int* treePtrs[6];
for (int i = 0; i < 6; i++) treePtrs[i] = trees[i];
int returnSize;
int* returnColumnSizes;
int** result = outerTrees(treePtrs, 6, NULL, &returnSize, &returnColumnSizes);
for (int i = 0; i < returnSize; i++) {
printf("[%d,%d] ", result[i][0], result[i][1]);
free(result[i]);
}
free(result);
free(returnColumnSizes);
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.