537. Erect the Fence (Convex Hull Problem)
Input:
[[1,1],[2,2],[2,0],[2,4],[3,3],[4,2]]
Output:
[[1,1],[2,0],[4,2],[3,3],[2,4]]
Explanation:Input:
[[1,2],[2,2],[4,2]]
Output:
[[1,2],[2,2],[4,2]]
Explanation:Last updated
Was this helpful?
Input:
[[1,1],[2,2],[2,0],[2,4],[3,3],[4,2]]
Output:
[[1,1],[2,0],[4,2],[3,3],[2,4]]
Explanation:Input:
[[1,2],[2,2],[4,2]]
Output:
[[1,2],[2,2],[4,2]]
Explanation:Last updated
Was this helpful?
Was this helpful?
1. sort points based on the x value as first priority, then y value
2. build the lower hull: compare the cross product of second_last, last and current point, if negative, means the
previous vec made the clockwise turn, at which we should get rid of the last value as it is not a eligible vertex.
3. build the upper hull: repeat the step 2 with reversely traversing the vector.class Solution {
public:
int orientation(Point &p, Point &q, Point &r) {
return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
}
vector<Point> outerTrees(vector<Point>& points) {
if (points.size() <= 3)
return points;
//sort lexicographically
sort(points.begin(), points.end(), [](Point &p, Point &q) {
return p.x < q.x || (p.x == q.x && p.y < q.y);
});
vector<Point> ans;
//lower hull
for (int i = 0; i < points.size(); ++i) {
while (ans.size() >= 2 && orientation(ans[ans.size() - 2], ans[ans.size() - 1], points[i]) < 0)
ans.pop_back();
ans.push_back(points[i]);
}
// remove the last point as it will be included in the upper hull
ans.pop_back();
// upper hull
for (int i = points.size() - 1; i >= 0; --i) {
while (ans.size() >= 2 && orientation(ans[ans.size() - 2], ans[ans.size() - 1], points[i]) < 0)
ans.pop_back();
ans.push_back(points[i]);
}
// remove the last point as it was included as the first point explored;
ans.pop_back();
return ans;
}
};class Solution {
public:
vector<Point> outerTrees(vector<Point>& points) {
// Andrew's monotone chain method
int n = points.size();
vector<Point> ans;
sort(points.begin(), points.end(), mycompare);
// left to right
for (int i = 0; i < n; ++i) {
while (ans.size() > 1 && orientation(ans[ans.size()-2], ans.back(), points[i]) < 0)
ans.pop_back();
ans.push_back(points[i]);
}
// if all points along a line, ans.size() is n after left to right procedure
if (ans.size() == n) return ans;
// right to left
for (int i = n-2; i >= 0; --i) {
while (ans.size() > 1 && orientation(ans[ans.size()-2], ans.back(), points[i]) < 0)
ans.pop_back();
ans.push_back(points[i]);
}
ans.pop_back();
return ans;
}
private:
static bool mycompare(Point& a, Point& b) {
return a.x < b.x || (a.x == b.x && a.y < b.y);
}
int orientation(Point& a, Point& b, Point& c) {
return (b.x-a.x)*(c.y-b.y) - (b.y-a.y)*(c.x-b.x);
}
}; vector<Point> outerTrees(vector<Point>& points) {
if(points.size() < 3) return points;
auto cmp = [](Point& a, Point& b) -> bool {
return a.x < b.x || (a.x == b.x && a.y < b.y);
};
sort(points.begin(), points.end(), cmp);
vector<Point> stack;
stack.push_back(points[0]);
stack.push_back(points[1]);
//left to right;
for(int i = 2; i < points.size(); ++i) {
while(stack.size() > 1) {
auto &t1 = stack.back();
auto &t2 = stack[stack.size() - 2];
if(isRightTurn(t2, t1, points[i])) break;
else stack.pop_back();
}
stack.push_back(points[i]);
}
int n = stack.size();
if(n == points.size()) return stack; //check if linear
stack.push_back(points[points.size() - 2]);
//right to left;
for(int i = points.size() - 3; i >= 0; --i) {
while(stack.size() > n) {
auto &t1 = stack.back();
auto &t2 = stack[stack.size() - 2];
if(isRightTurn(t2, t1, points[i])) break;
else stack.pop_back();
}
stack.push_back(points[i]);
}
stack.pop_back();
return stack;
}
bool isRightTurn(Point &a, Point &b, Point &c) {
return (b.x - a.x) * (c.y - a.y) - (b.y - a.y) * (c.x - a.x) <= 0;
}def outerTrees(self, A):
def sign(p, q, r):
return cmp((p.x - r.x)*(q.y - r.y), (p.y - r.y)*(q.x - r.x))
def drive(hull, r):
hull.append(r)
while len(hull) >= 3 and sign(*hull[-3:]) < 0:
hull.pop(-2)
return hull
A.sort(key = lambda p: (p.x, p.y))
lower = reduce(drive, A, [])
upper = reduce(drive, A[::-1], [])
return list(set(lower + upper))1)Find the bottom-most point by comparing y coordinate of all points. If there are two points with same y value, then the point with smaller x coordinate value is considered. Let the bottom-most point be P0. Put P0 at first position in output hull.
2)Consider the remaining n-1 points and sort them by polor angle in counterclockwise order around points[0]. If polor angle of two points is same, then put the nearest point first.
3After sorting, check if two or more points have same angle. If two more points have same angle, then remove all same angle points except the point farthest from P0. Let the size of new array be m.
4)If m is less than 3, return (Convex Hull not possible)
5)Create an empty stack ‘S’ and push points[0], points[1] and points[2] to S.
6)Process remaining m-3 points one by one. Do following for every point ‘points[i]’
4.1)Keep removing points from stack while
orientation
of following 3 points is not counterclockwise (or they don’t make a left turn).
a) Point next to top in stack
b) Point at the top of stack
c) points[i]
4.2)Push points[i] to S
5)Print contents of S/**
* Definition for a point.
* struct Point {
* int x;
* int y;
* Point() : x(0), y(0) {}
* Point(int a, int b) : x(a), y(b) {}
* };
*/
class Solution {
struct pointsComparator{
Point p0;
bool operator() (const Point & p1, const Point& p2){
int o = orientation(p0, p1, p2);
if(o == 0) return distSq(p0, p2)>= distSq(p0, p1);
return o == 2;
}
pointsComparator(Point p): p0(p){}
};
// int compare(const void *vp1, const void *vp2){
// Point *p1 = (Point *) vp1;
// Point *p2 = (Point *) vp2;
// }
static int distSq(Point p1, Point p2) {
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}
static int orientation(Point a, Point b, Point c){
int val = (b.x - a.x)*(c.y-b.y) - (b.y - a.y)*(c.x - b.x);
if(val == 0) return 0;
return (val > 0)? 2:1;
}
// Point nextTotop(stack<Point> &s){
// Point p = s.top();
// s.pop();
// Point res = s.top();
// s.push(p);
// return res;
// }
// void swap(Point &p1, Point& p2){
// Point temp = p1;
// p1 = p2;
// p2 = temp;
// }
public:
vector<Point> outerTrees(vector<Point> points) {
int n = points.size();
if (n <= 3) {
return points;
}
// Find the bottommost point
int ymin = points[0].y, min = 0;
for (int i = 1; i < n; i++) {
int y = points[i].y;
// Pick the bottom-most or chose the left most point in case of tie
if ((y < ymin) || (ymin == y && points[i].x < points[min].x)) {
ymin = points[i].y, min = i;
}
}
// Place the bottom-most point at first position
Point temp = points[0];
points[0] = points[min];
points[min] = temp;
// Sort n-1 points with respect to the first point.
// A point p1 comes before p2 in sorted ouput
// if p2 has larger polar angle (in counterclockwise direction) than p1
// In the tied case, the one has smaller distance from p0 comes first
Point p0 = points[0];
sort(points.begin(), points.end(), pointsComparator(p0));
//As we need to output all the vertices instead of extreme points
//We need to sort the points with the same largest polar angle w.r.p. p0 in another way to break tie
//Closer one comes last
Point pn = points.back();
if (orientation(p0, points[1], pn) != 0) {
int idx = n-1;
while (orientation(p0, points[idx], pn) == 0) {
idx--;
}
reverse(points.begin() + idx + 1, points.end());
}
// Create an empty stack and push first three points to it.
vector<Point> vertices;
vertices.push_back(points[0]);
vertices.push_back(points[1]);
vertices.push_back(points[2]);
// Process remaining n-3 points
for (int i = 3; i < n; i++) {
// Keep removing top while the angle formed by
// points next-to-top, top, and points[i] makes a right (in clockwise) turn
while (orientation(vertices[vertices.size() - 2], vertices.back(), points[i]) == 1) {
vertices.pop_back();
}
vertices.push_back(points[i]);
}
return vertices;
}
};public class Solution {
public List<Point> outerTrees(Point[] points) {
Set<Point> result = new HashSet<>();
// Find the leftmost point
Point first = points[0];
int firstIndex = 0;
for (int i = 1; i < points.length; i++) {
if (points[i].x < first.x) {
first = points[i];
firstIndex = i;
}
}
result.add(first);
Point cur = first;
int curIndex = firstIndex;
do {
Point next = points[0];
int nextIndex = 0;
for (int i = 1; i < points.length; i++) {
if (i == curIndex) continue;
int cross = crossProductLength(cur, points[i], next);
if (nextIndex == curIndex || cross > 0 ||
// Handle collinear points
(cross == 0 && distance(points[i], cur) > distance(next, cur))) {
next = points[i];
nextIndex = i;
}
}
// Handle collinear points
for (int i = 0; i < points.length; i++) {
if (i == curIndex) continue;
int cross = crossProductLength(cur, points[i], next);
if (cross == 0) {
result.add(points[i]);
}
}
cur = next;
curIndex = nextIndex;
} while (curIndex != firstIndex);
return new ArrayList<Point>(result);
}
private int crossProductLength(Point A, Point B, Point C) {
// Get the vectors' coordinates.
int BAx = A.x - B.x;
int BAy = A.y - B.y;
int BCx = C.x - B.x;
int BCy = C.y - B.y;
// Calculate the Z coordinate of the cross product.
return (BAx * BCy - BAy * BCx);
}
private int distance(Point p1, Point p2) {
return (p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y);
}
}