解法
给点集求凸包的问题,有很多种算法
一个比较简单的算法是Monotone chain算法
它需要将点排序,在结点排好序的情况下是的
- 将点按x,y从小到大排序
- 求凸包下界
lower,正向遍历所有节点,判断当前节点在栈顶两个节点构成的向量的左边还是右边 - 如果在左边,那么把当前节点入栈
- 如果在右边,那么pop栈顶的节点
- 重复步骤2,直到遍历完成
然后求凸包上界upper,它需要反向遍历所有节点,步骤和上述一样。
判断新节点在向量左边还是右边需要用到叉积的一些知识。
由于本题中,在一条直线上的3个点也要算到边界里,所以cross里的判断是>=0,也因此upper和lower会有除了头尾之外的次,所以最后要去重
如果一条直线只算头尾的话,那么cross里应该是>0,并且最后返回lower[:-1]+upper[:-1]即可
# Definition for a point.
# class Point(object):
# def __init__(self, a=0, b=0):
# self.x = a
# self.y = b
class Solution(object):
def outerTrees(self, points):
"""
:type points: List[Point]
:rtype: List[Point]
"""
n = len(points)
if n<=2:
return points
points = sorted(points, key=lambda x:(x.x,x.y))
def cross(i,j,k):
x1,y1 = points[j].x-points[i].x,points[j].y-points[i].y
x2,y2 = points[k].x-points[i].x,points[k].y-points[i].y
return x1*y2-x2*y1>=0
lower = []
for i in xrange(n):
while len(lower)>=2 and not cross(lower[-2],lower[-1],i):
lower.pop()
lower.append(i)
upper = []
for i in xrange(n-1,-1,-1):
while len(upper)>=2 and not cross(upper[-2],upper[-1],i):
upper.pop()
upper.append(i)
return map(lambda x:points[x],set(lower)|set(upper))