### 587. Erect the Fence
题目:
难度:
Hard
思路
题目要求用一个围栏把所有的点(🌲)围起来,然后求处于围栏上点(🌲)的集合。
我们可以发现,从最左边的那个点一直往右走,只要一直都是走的逆时针方向,那么我们一定可以找到这条围栏。那么接下来就考虑最简单的情况,
- 只有两个点```p```和```q```,我们从```p```走到```q```,当```p```到原点这条直线的斜率小于```q```到原点这条直线的斜率时,```p->q```就是沿逆时针方向走的;
- 接下来考虑3个点:```p,q,r```,以```p```为参照点(即前面的原点),那么从```q```走到```r```的时候,只要```q```到```q```这条直线的斜率小于```r```到```p```这条直线的斜率,```q->r```就是沿逆时针方向走的。
因此,我们只要构建一个```orientation```函数,就可以判断出目前我们的围栏是不是沿着逆时针在走下去了。
我们用一个```stack```来存放目前认为在围栏上的点的集合,然后把所有的点按照指定规则排好序:```先按照点的x坐标升序排列,如果x相等则按照点的y坐标升序排列```。这样我们依次取点,只要```stack```里面的点大于等于```2```个我们就要无限进行判断是否走的是逆时针,如果不是就把```stack```里面最后那个点```pop```出去(可能一直```pop```到只剩一个点),否则就把目前的这个点加入到```stack```中去,因为目前它还是在逆时针方向上的。
从左往右走完一遍```points```之后,我们围栏的下部分```lower hull```就构建好了,此时我们还要构建围栏的```upper hull```,因此我们将```points```逆序一下,从右往左再来一次遍历,仍然看是否走的是逆时针。但是这次遍历我们需要进行一个判断,就是之前放进```stack```的点,此时我们还是会经过它,如果它已经在```stack```里面了,我们就不需要再加进去了,同时这样也避免了我们把最左边的点重复加进去。
```python
python
# import functools
class Solution:
def outerTrees(self, points):
"""
:type points: List[Point]
:rtype: List[Point]
"""
def orientation(p, q, r):
return (q.y - p.y)*(r.x - p.x) - (r.y - p.y)*(q.x - p.x)
# def myComparator(p,q):
# return p.x - q.x if p.x != q.x else p.y - q.y
stack= []
# points.sort(key = functools.cmp_to_key(myComparator))
points.sort(key = lambda p: (p.x, p.y))
for i in range(len(points)):
while (len(stack) >= 2 and orientation(stack[-2],stack[-1],points[i]) > 0):
stack.pop()
stack.append(points[i])
points.reverse();
for i in range(len(points)):
while (len(stack) >= 2 and orientation(stack[-2],stack[-1],points[i]) > 0):
stack.pop()
if points[i] not in stack:
stack.append(points[i])
return stack
```
简化python版本
```python
class Solution(object):
def outerTrees(self, points):
"""
:type points: List[Point]
:rtype: List[Point]
"""
def orientation(p, q, r):
return (q.y - p.y) * (r.x - q.x) - \
(q.x - p.x) * (r.y - q.y)
hull = []
points.sort(key=lambda p: (p.x, p.y))
for i in itertools.chain(xrange(len(points)), \
reversed(xrange(len(points)))):
while len(hull) >= 2 and \
orientation(hull[-2], hull[-1], points[i]) > 0:
hull.pop()
hull.append(points[i])
return list(set(hull))
```
下面是小傅大神的代码,本来想叫‘’傅神‘’的,结果这名字🤦♂️(手动捂脸)[小傅每日一题587](https://www.bilibili.com/video/av15446980/)
另外其中的```stack.pop()```这行代码注释掉也是可以的
```java
java
class Solution {
public List outerTrees(Point[] points) {
List res = new ArrayList();
Arrays.sort(points, new Comparator(){
@Override
public int compare(Point p, Point q){
return p.x == q.x ? p.y - q.y : p.x - q.x;
}
});
Stack stack = new Stack<>();
for (int i = 0; i < points.length; i++){
while(stack.size() >= 2 && orientation(stack.get(stack.size() - 2), stack.peek(), points[i]) > 0){
stack.pop();
}
stack.push(points[i]);
}
//stack.pop();
for (int i = points.length - 1; i >= 0; i--){
while(stack.size() >= 2 && orientation(stack.get(stack.size() - 2), stack.peek(), points[i]) > 0){
stack.pop();
}
stack.push(points[i]);
}
res.addAll(new HashSet<>(stack));
return res;
}
public int orientation(Point p, Point q, Point r){
return (q.y - p.y)*(r.x - p.x) - (r.y - p.y)*(q.x - p.x);
}
}
```
Author: Keqi Huang
If you like it, please spread your support
![Support](https://github.com/Lisanaaa/myTODOs/blob/master/WechatIMG17.jpeg)