LeetCode 解题 Day 03

587. Erect the Fence

https://leetcode.com/problems/erect-the-fence/


题目解释

你有n棵树的座标,请你用栅栏把树全部围起来,因为栅栏太贵了所以请围出最短的距离

这题简单来说就是凸包(convex hull)的问题


解法1:

这个解法是Jarvis' March又叫做礼物包装演算法(Gift Wrapping Algorithm),概念是先找出最外侧的任意点,之後用外积找出其他也是最外侧的点,总之先上程序码吧!

程序码:

class Solution:
    def outerTrees(self, trees: List[List[int]]) -> List[List[int]]:

        if len(trees) <= 3:
            return trees
        
        start = self.find_start_pos(trees)
        hull = []
        p = start
        q = 0
        
        while True:
            
            q = (p + 1) % len(trees)
            
            for i in range(len(trees)):
                if self.orientation(trees[p], trees[i], trees[q]) < 0: 
                # i在逆时钟方向,可以当作最外圈的候选
                    q = i
            
            for i in range(len(trees)):
                if i != p and i != q and self.orientation(trees[p], trees[i], trees[q]) == 0: 
                # 同一条线上
                    x = trees[p][0] <= trees[i][0] and trees[i][0] <= trees[q][0] \
                            or trees[p][0] >= trees[i][0] and trees[i][0] >= trees[q][0]
                    y = trees[p][1] <= trees[i][1] and trees[i][1] <= trees[q][1] \
                            or trees[p][1] >= trees[i][1] and trees[i][1] >= trees[q][1]
                    
                    if x and y:
                        hull.append(trees[i]);
                    
            hull.append(trees[q])
            p = q
            
            if p == start:
                break
        
        return hull
    
    def find_start_pos(self, trees):
        # 找起始的点
        start = 0
        for i, tree in enumerate(trees):
            if math.sqrt(tree[0]**2 + tree[1]**2) < math.sqrt(trees[start][0]**2 + trees[start][1]**2):
                start = i
                
        return start
    
    def orientation(self, p, q, r):
        #外积
        return (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]) 

步骤:

  1. 先找出任意最外侧的点,因为这题已经限制 x,y 不会有负数了,所以我找最接近 (0,0) 的当起始点 p0
  2. 找起始点以外的第二个点 p1 ,接着用回圈让所有点轮流当第三个点p2,用 (p0,p1) 的向量和 (p1,p2) 的向量做外积,判断p2是不是逆时钟方向的点;简单来说就是看 p2 是不是在 (p0,p1) 向量右边
  3. 找到p2後,检查是不是有点在 p0、p2 之间,是的话也要存起来

但是Time Limit Exceeded

这个方法的时间复查度是 O(mn)m代表最外圈有几个点,如果最外圈点很多的话就会超过系统限制的时间


闲聊:

今天的题目对我来说很难,之前没有接触过凸包的问题,所以学到新东西了

解法1的时间会超过系统要求的限制,所以要用其他的演算法

但是,我懒了/images/emoticon/emoticon67.gif

过几天後再补上OK的解法吧!


<<:  Day3 理解 golang slice 用法及原理 III

>>:  我们注定成不了海贼王

DAY12:玉山人工智慧挑战赛-中文手写字辨识(前言)

参赛契机 之前参加资策会,结训时都会做个专题啦,但因为我自己对我们组的专题挺不满意,而且对於深度学习...

[day18] 追踪 & 封锁事件处理

当获得一个新会员,会希望使用者能够了解如何使用系统,会提供使用者一份指引如何使用,同时也希望使用者尽...

#3. Expanding Cards(原生JS版)+ 用tailwindcss玩grid排版

今日专案进度 A. 用grid方式将专案重新排版(透过tailwind css) B. 使用vue-...

成员 7 人:怪异的是,我本来很讨厌你!

你的公司,订好制度了吗? ......还没的话,不要看这篇。 <<< 回头分隔线:...

【C++】Encryption and Decryption

在学习Encryption 跟Decryption前~ ASCII电脑编码系统是必须要知道的。 AS...