• Leetcode 587.安装栅栏


    安装栅栏

    在一个二维的花园中,有一些用 (x, y) 坐标表示的树。由于安装费用十分昂贵,你的任务是先用最短的绳子围起所有的树。只有当所有的树都被绳子包围时,花园才能围好栅栏。你需要找到正好位于栅栏边界上的树的坐标。

       

    示例 1:

    输入: [[1,1],[2,2],[2,0],[2,4],[3,3],[4,2]]

    输出: [[1,1],[2,0],[4,2],[3,3],[2,4]]

    解释:

    示例 2:

    输入: [[1,2],[2,2],[4,2]]

    输出: [[1,2],[2,2],[4,2]]

    解释:

    即使树都在一条直线上,你也需要先用绳子包围它们。

       

    注意:

    1. 所有的树应当被围在一起。你不能剪断绳子来包围树或者把树分成一组以上。
    2. 输入的整数在 0 到 100 之间。
    3. 花园至少有一棵树。
    4. 所有树的坐标都是不同的。
    5. 输入的点没有顺序。输出顺序也没有要求。

    Graham扫描法

    我给了它一个新名字,边界扫描法。用到的性质和解法二密切相关,首先也需要对某个维度进行从小达到排序。这样我们就能确定其中一个顶点了,我们选择横坐标最小的那个点作为整个坐标的原点。

    算法步骤:

    1. 把所有点放在二维坐标系中,则纵坐标最小的点一定是凸包上的点,如图中的P0。

    2. 把所有点的坐标平移一下,使 P0 作为原点,如上图。

    3. 计算各个点相对于 P0 的幅角 α ,按从小到大的顺序对各个点排序。当 α 相同时,距离 P0 比较近的排在前面。例如上图得到的结果为 P1,P2,P3,P4,P5,P6,P7,P8。我们由几何知识可以知道,结果中第一个点 P1 和最后一个点 P8 一定是凸包上的点。

    (以上是准备步骤,以下开始求凸包)

    以上,我们已经知道了凸包上的第一个点 P0 和第二个点 P1,我们把它们放在栈里面。现在从步骤3求得的那个结果里,把 P1 后面的那个点拿出来做当前点,即 P2 。接下来开始找第三个点:

    4. 连接P0和栈顶的那个点,得到直线 L 。看当前点是在直线 L 的右边还是左边。如果在直线的右边就执行步骤5;如果在直线上,或者在直线的左边就执行步骤6。

    5. 如果在右边,则栈顶的那个元素不是凸包上的点,把栈顶元素出栈。执行步骤4。

    6. 当前点是凸包上的点,把它压入栈,执行步骤7。

    7. 检查当前的点 P2 是不是步骤3那个结果的最后一个元素。是最后一个元素的话就结束。如果不是的话就把 P2 后面那个点做当前点,返回步骤4。

     1 public class Solution {
     2     public int orientation(Point p, Point q, Point r) {
     3         return (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
     4     }
     5     public int distance(Point p, Point q) {
     6         return (p.x - q.x) * (p.x - q.x) + (p.y - q.y) * (p.y - q.y);
     7     }
     8     private static Point bottomLeft(Point[] points) {
     9         Point bottomLeft = points[0];
    10         for (Point p: points)
    11             if (p.y < bottomLeft.y)
    12                 bottomLeft = p;
    13         return bottomLeft;
    14     }
    15     public List <Point> outerTrees(Point[] points) {
    16         if (points.length <= 1)
    17             return Arrays.asList(points);
    18         Point bm = bottomLeft(points);
    19         Arrays.sort(points, new Comparator< Point >() {
    20             public int compare(Point p, Point q) {
    21                 double diff = orientation(bm, p, q) - orientation(bm, q, p);
    22                 if (diff == 0)
    23                     return distance(bm, p) - distance(bm, q);
    24                 else
    25                     return diff > 0 ? 1 : -1;
    26             }
    27         });
    28         int i = points.length - 1;
    29         while (i >= 0 && orientation(bm, points[points.length - 1], points[i]) == 0)
    30             i--;
    31         for (int l = i + 1, h = points.length - 1; l < h; l++, h--) {
    32             Point temp = points[l];
    33             points[l] = points[h];
    34             points[h] = temp;
    35         }
    36         Stack < Point > stack = new Stack< >();
    37         stack.push(points[0]);
    38         stack.push(points[1]);
    39         for (int j = 2; j < points.length; j++) {
    40             Point top = stack.pop();
    41             while (orientation(stack.peek(), top, points[j]) > 0)
    42                 top = stack.pop();
    43             stack.push(top);
    44             stack.push(points[j]);
    45         }
    46         return new ArrayList<>(stack);
    47     }
    48 }
  • 相关阅读:
    讲述Sagit.Framework解决:双向引用导致的IOS内存泄漏(上)
    Sagit.Framework For IOS 开发框架入门教程4:注册页布局-被消灭的变量
    Sagit.Framework For IOS 开发框架入门教程3:Start引导页及框架布局和隐藏事件的内幕
    Sagit.Framework For IOS 开发框架入门开发教程2:一行代码实现引导页
    Sagit.Framework For IOS 开发框架入门开发教程1:框架下载与环境配置
    CYQ.Data 正式支持 DotNET Core 版本发布
    IT连创业系列:App产品上线后,运营怎么搞?(中)
    IT连创业系列:App产品上线后,运营怎么搞?(上)
    分享:苹果APP更新上架被拒的另一种理由(Safety
    IT连创业系列:说说苹果商店AppStore上架App应用前后遇到的那些神坑
  • 原文地址:https://www.cnblogs.com/kexinxin/p/10381397.html
Copyright © 2020-2023  润新知