扫描线Sweep Line算法总结

Number of Airplanes in the Sky 思路:经典扫描线算法:把interval起飞和降落做为event,全部打散,按照时间排列,同时时间相等的,按照降落在前面,起飞在后面进行排序;最后再扫一遍,遇见start,count++,遇见end,count--,然后最后中间出现的最大值,就是题目所求。

/**
 * Definition of Interval:
 * public classs Interval {
 *     int start, end;
 *     Interval(int start, int end) {
 *         this.start = start;
 *         this.end = end;
 *     }
 * }
 */

public class Solution {
    /**
     * @param airplanes: An interval array
     * @return: Count of airplanes are in the sky.
     */
    private class Node {
        public int time;
        public int flag;
        public Node(int time, int flag) {
            this.time = time;
            this.flag = flag;
        }
    }

    public int countOfAirplanes(List airplanes) {
        int count = 0;
        List list = new ArrayList();
        for(Interval interval: airplanes) {
            list.add(new Node(interval.start, 1));
            list.add(new Node(interval.end, -1));
        }
        Collections.sort(list, (a, b) -> a.time != b.time ? a.time - b.time : a.flag - b.flag);
        int maxplane = 0;
        for(int i = 0; i < list.size(); i++) {
            Node node = list.get(i);
            if(node.flag == 1) {
                count++;
            } else {
                count--;
            }
            maxplane = Math.max(maxplane, count);
        }
        return maxplane;
    }
}

Meeting Rooms II 思路:题目跟上面飞机一模一样,代码都是一样的。

class Solution {
    private class Node {
        public int time;
        public int flag;
        public Node(int time, int flag) {
            this.time = time;
            this.flag = flag;
        }
    }
    
    public int minMeetingRooms(int[][] intervals) {
        if(intervals == null || intervals.length == 0 || intervals[0].length == 0) {
            return 0;
        }
        List list = new ArrayList();
        for(int i = 0; i < intervals.length; i++) {
            list.add(new Node(intervals[i][0], 1));
            list.add(new Node(intervals[i][1], -1));
        }
        
        Collections.sort(list, (a, b) -> (
                a.time != b.time ? a.time - b.time : a.flag - b.flag));
        
        int count = 0;
        int maxcount = 0;
        for(int i = 0; i < list.size(); i++) {
            Node node = list.get(i);
            if(node.flag == 1) {
                count++;
            } else {
                count--;
            }
            maxcount = Math.max(maxcount, count);
        }
        return maxcount;
    }
}

Time Intersection 思路:扫描线算法,注意的是,阈值发生变化的时候,收集数据,一定要在count = 2的时候收集。

/**
 * Definition of Interval:
 * public classs Interval {
 *     int start, end;
 *     Interval(int start, int end) {
 *         this.start = start;
 *         this.end = end;
 *     }
 * }
 */

public class Solution {
    /**
     * @param seqA: the list of intervals
     * @param seqB: the list of intervals
     * @return: the time periods
     */
    
    private class Node {
        public int time;
        public int flag;
        public Node(int time, int flag) {
            this.time = time;
            this.flag = flag;
        }
    } 
    
    private class NodeComparator implements Comparator {
        @Override
        public int compare(Node a, Node b) {
            if(a.time != b.time) {
                return a.time - b.time;
            } else {
                return a.flag - b.flag; // define flag 1 is online, 0 is offline;
            }
        }
    }
    
    public List timeIntersection(List seqA, List seqB) {
        List result = new ArrayList();
        if(seqA == null || seqA.size() == 0 || seqB == null || seqB.size() == 0) {
            return result;
        }
        
        int n = seqA.size();
        int m = seqB.size();
        Node[] nodes = new Node[n * 2 + m * 2];
        int index = 0;
        for(int i = 0; i < n; i++) {
            nodes[index++] = new Node(seqA.get(i).start, 1);
            nodes[index++] = new Node(seqA.get(i).end, 0);
        }
        for(int i = 0; i < m; i++) {
            nodes[index++] = new Node(seqB.get(i).start, 1);
            nodes[index++] = new Node(seqB.get(i).end, 0);
        }
        
        Arrays.sort(nodes, new NodeComparator());
        int count = 0;
        int start = 0;
        int end = 0;
        for(int i = 0; i < nodes.length; i++) {
            if(nodes[i].flag == 1) {
                count++;
                if(count == 2) {
                    start = nodes[i].time;
                }
            }
            if(nodes[i].flag == 0) {
                if(count == 2) { //每次都是阈值发生变化的时候,收集interval;
                    end = nodes[i].time;
                    result.add(new Interval(start, end));
                    start = 0;
                    end = 0;
                }
                count--;
            }
        }
        return result;
    }
}

 思路2:这题因为数据是sorted,因为A和B都是sorted,那么跟merge array一样,可以用打擂台的方式,每次踢走一个。
如果Max(startA, startB) < Min(endA, endB)则加入相交的interval 然后看A, B end 谁大,谁留下,另外一个踢走;O(N+M)

// 因为数据是sorted,那么就按照overlap来扫描,也就是start取最大值,end取最小值,
// 如果start< end,表明有overlap,否则不会有overlap,同时end较小的扔掉,较大的留下;

/**
 * Definition of Interval:
 * public classs Interval {
 *     int start, end;
 *     Interval(int start, int end) {
 *         this.start = start;
 *         this.end = end;
 *     }
 * }
 */

public class Solution {
    /**
     * @param seqA: the list of intervals
     * @param seqB: the list of intervals
     * @return: the time periods
     */
    public List timeIntersection(List seqA, List seqB) {
        List result = new ArrayList();
        if(seqA == null || seqA.size() == 0 || seqB == null || seqB.size() == 0) {
            return result;
        }
        
        int aIndex = 0;
        int bIndex = 0;
        
        // 因为数据是sorted,那么就按照overlap来扫描,也就是start取最大值,end取最小值,
        // 如果start< end,表明有overlap,否则不会有overlap,同时end较小的扔掉,较大的留下;
        while(aIndex < seqA.size() && bIndex < seqB.size()) {
            int start = Math.max(seqA.get(aIndex).start, seqB.get(bIndex).start);
            int end = Math.min(seqA.get(aIndex).end, seqB.get(bIndex).end);
            if(start < end) {
                result.add(new Interval(start, end));
            }
            if(seqA.get(aIndex).end < seqB.get(bIndex).end) {
                aIndex++;
            } else {
                bIndex++;
            }
        }
        return result;
    }
}

Meeting Scheduler:  跟上面一样,两个array按照start,sort之后,打擂台的方式,判断如果相交,那么end - start >= duration那么就收集[start, start + duration] 返回,否则,end大的留下,小的扔掉;T( mlogm + nlogn);

class Solution {
    public List minAvailableDuration(int[][] slots1, int[][] slots2, int duration) {
        List list = new ArrayList();
        Arrays.sort(slots1, (a, b) -> (a[0] - b[0]));
        Arrays.sort(slots2, (a, b) -> (a[0] - b[0]));
        
        int a = 0; int b = 0;
        while(a < slots1.length && b < slots2.length) {
            int start = Math.max(slots1[a][0], slots2[b][0]);
            int end = Math.min(slots1[a][1], slots2[b][1]);
            
            if(start < end && end - start >= duration) {
                list.add(start);
                list.add(start + duration);
                return list;
            } else {
                if(slots1[a][1] > slots2[b][1]) {
                    b++;
                } else {
                    a++;
                }
            }
        }
        return list;
    }
}

Skyline problem: 思路:扫描线算法;起飞的时候才加入一堆高度进行排序判断最高height,下降的时候,要remove 当前的高度,由于下降的点刚开始存的时候就是负数,所以remove的时候就是remove -负数。不参加评选了。还有注意点就是pq刚开始有可能是空的时候,curheight是0. 否则会报NPE;

class Solution {
    private class Node {
        public int x;
        public int height;
        public Node(int x, int height) {
            this.x = x;
            this.height = height;
        }
    }
    
    public List> getSkyline(int[][] buildings) {
        List> lists = new ArrayList>();
        if(buildings == null || buildings.length == 0 || buildings[0].length == 0) {
            return lists;
        }
        
        PriorityQueue pq = new PriorityQueue((a, b) -> (b - a));
        List nodes = new ArrayList();
        for(int i = 0; i < buildings.length; i++) {
            nodes.add(new Node(buildings[i][0], buildings[i][2]));
            nodes.add(new Node(buildings[i][1], -buildings[i][2]));
        }
        
        Collections.sort(nodes, (a, b) -> (a.x != b.x ? a.x - b.x : b.height - a.height));
        int preheight = 0;
        int curheight = 0;
        for(int i = 0; i < nodes.size(); i++) {
            Node node = nodes.get(i);
            if(node.height > 0) {
                // 起飞的时候,加入pq进行排序;
                pq.offer(node.height);
            } else {
                // 因为下降的点,height是负数,所以这里要remove -height;
                pq.remove(-node.height);
            }
            // 注意这里要判断pq是否为空,为空就是0,不为空才是peek;
            curheight = pq.isEmpty() ? 0 : pq.peek();
            if(curheight != preheight) {
                List list = new ArrayList();
                list.add(node.x);
                list.add(curheight);
                lists.add(list);
                preheight = curheight;
            }
        }
        return lists;
    }
}

 

你可能感兴趣的:(Sweep,Line,总结)