zoukankan      html  css  js  c++  java
  • 高级数据结构之线段树与扫描线算法

    1. 扫描线算法

    1)原理:

    平面扫描线算法通常由扫描线、事件点、当前扫描事件点集合构成:通过扫描线按照某一方向依次扫描,扫描事件点,检查事件点状态,然后新增或删除事件点以更新事件点集合。

    2)看一道经典的问题:

    Lintcode391. 数飞机

    给出飞机的起飞和降落时间的列表,用 interval 序列表示. 请计算出天上同时最多有多少架飞机?

    这道题看起来很简单,但是我的做法超时了:

    public class Solution {
        /**
         * @param airplanes: An interval array
         * @return: Count of airplanes are in the sky.
         */
        public int countOfAirplanes(List<Interval> airplanes) {
            // write your code here
            if (airplanes.size() == 0) return 0;
            int maxTime = Integer.MIN_VALUE;
            for (Interval interval : airplanes) {
                maxTime = Math.max(maxTime, interval.end);
            }
            int[] timePoint = new int[maxTime + 1];
            for (int i = 1; i <= maxTime; i++) {
                int showTime = 0;
                for (Interval interval : airplanes) {
                    if (interval.start <= i && interval.end > i) {
                        showTime++;
                    }
                }
                timePoint[i] = showTime;
            }
            int res = Integer.MIN_VALUE;
            for (int i = 1; i <= maxTime; i++) {
                res = Math.max(res, timePoint[i]);
            }
            return res;
        }
    }

    这个解法是很细粒度的扫描,就是每个时刻都要扫描一次,所以当最长事件很大时,我开的数据就很大,就需要扫描很长的数组。

    那么可否粗粒度的扫描呢?答那是可以的,就是只需要检查起点和终点。因为一段时间的构成就是起点和终点,那么涉及到事件点集合的变化就是起点的出现和终点的出现。

    那么具体是如何变化的呢?想一想,如果一个起点出现,会发生什么,就说明当前时刻又有一个时间段出现了,如果终点出现,就说明当前时刻结束了一个时间段。

    那么我们可以维护一个count,来记录实时事件点的变化。 当起点出现,count++;终点出现count--;哈,前提是这些时间段应该顺序排列。

    ok,按这个思路改了代码,ac

    public class Solution {
        /**
         * @param airplanes: An interval array
         * @return: Count of airplanes are in the sky.
         */
         
        class Point {
            int time;
            int flag;
            public Point(int t, int f) {
                time = t;
                flag = f;
            }
        }
        public int countOfAirplanes(List<Interval> airplanes) {
            // write your code here
            List<Point> points = new ArrayList<>();
            for (Interval interval : airplanes) {
                points.add(new Point(interval.start, 1));
                points.add(new Point(interval.end, 0));
            }
            Collections.sort(points, new Comparator<Point>(){
                public int compare(Point p1, Point p2) {
                    if (p1.time == p2.time) return p1.flag - p2.flag;
                    return p1.time - p2.time;
                }
            });
            int res = 0, count = 0;
            for (Point point : points) {
                if (point.flag == 1) count++;
                else count--;
                res = Math.max(res, count);
            }
            return res;
        }
    }

    参考资料:

    http://openinx.github.io/2013/01/01/plane-sweep-thinking/

  • 相关阅读:
    Postman初探
    web页面和本地数据对比问题
    Katalon Recorder初探
    Flask入门
    自我实现预言
    gulp 安装 依赖
    maven环境
    加解密 生成 X.509格式,DER编码,后缀名.cer。加密公钥证书
    我的魔法 公式找回中
    gulp 自动ftp至服务器时,处理开发 测试服务器地址问题
  • 原文地址:https://www.cnblogs.com/shawshawwan/p/9160726.html
Copyright © 2011-2022 走看看