扫描线算法模板 原理其实很容易想明白

391. 数飞机

中文
English

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

样例

Example 1:

Input: [(1, 10), (2, 3), (5, 8), (4, 7)]
Output: 3
Explanation:
The first airplane takes off at 1 and lands at 10.
The second ariplane takes off at 2 and lands at 3.
The third ariplane takes off at 5 and lands at 8.
The forth ariplane takes off at 4 and lands at 7.
During 5 to 6, there are three airplanes in the sky.

Example 2:

Input: [(1, 2), (2, 3), (3, 4)]
Output: 1
Explanation: Landing happen before taking off.

注意事项

如果多架飞机降落和起飞在同一时刻,我们认为降落有优先权。

 

下面这个是参考答案:

将起飞时间和降落时间放到同一个数组中, 标识出是起飞还是降落时间, 然后对数组排序.

遍历数组即可, 碰到起飞计数器加一, 碰到降落计数器减一. 维护最大值作为答案.

注意降落优先于起飞.——当心!!!

 

 

 

精選裡面的Python解答使用的是cmp這個function, 然而這個cmp function在Python 3.x已經不再作為sorted(), list.sort()的參數了 下面提供的版本是依照精選Python解答改過來的,適用於Python3.x版

def sorter(x, y):
    if x[0] != y[0]:
        return x[0] - y[0]
    return x[1] - y[1]


from functools import cmp_to_key
class Solution:
    
    def countOfAirplanes(self, airplanes):
        times = []
        for airplane in airplanes:
            times.append((airplane.start, 1))
            times.append((airplane.end, -1))

        times = sorted(times, key = cmp_to_key(sorter))

        count = 0
        max_count = 0
        for time, delta in times:
            count += delta
            max_count = max(max_count, count)
            
        return max_count
我的答案:
"""
Definition of Interval.
class Interval(object):
    def __init__(self, start, end):
        self.start = start
        self.end = end
"""

class Solution:
    """
    @param airplanes: An interval array
    @return: Count of airplanes are in the sky.
    """
    def countOfAirplanes(self, airplanes):
        # write your code here
        lines = []
        START, END = 1, 0
        for p in airplanes:
            lines.append((p.start, START))
            lines.append((p.end, END))
        
        lines.sort()
        
        c = 0
        ans = 0
        for p, flag in lines:
            if flag == START:
                c += 1
            else:
                c -= 1
            ans = max(ans, c)
        assert c == 0
        
        return ans

 直接排序就好了,因为python3里tuple的比较就是按照先比较第一个,再比较第二个!!!

>>> (1, 1) > (1, 2)
False
>>> (1, 1) < (1, 2)
True
>>> (2, 1) < (2, 3)
True
>>> (2, 1) > (2, 3)
False
>>> (2, 1) == (2, 1)
True

L = [(‘d’,2),(‘a’,4),(‘b’,3),(‘c’,2)]
L.sort(key=lambda x:(x[1],x[0])) 先按照数字排序,再按照字母排序
L
[(‘c’, 2), (‘d’, 2), (‘b’, 3), (‘a’, 4)]

 

919. 会议室 II

中文
English

给定一系列的会议时间间隔intervals,包括起始和结束时间[[s1,e1],[s2,e2],...] (si < ei),找到所需的最小的会议室数量。

样例

样例1

输入: intervals = [(0,30),(5,10),(15,20)]
输出: 2
解释:
需要两个会议室
会议室1:(0,30)
会议室2:(5,10),(15,20)

样例2

输入: intervals = [(2,7)]
输出: 1
解释:
只需要1个会议室就够了


"""
Definition of Interval.
class Interval(object):
    def __init__(self, start, end):
        self.start = start
        self.end = end
"""

class Solution:
    """
    @param intervals: an array of meeting time intervals
    @return: the minimum number of conference rooms required
    """
    def minMeetingRooms(self, intervals):
        # Write your code here
        lines = []
        S, E = 1, 0
        for i in intervals:
            lines.append((i.start, S))
            lines.append((i.end, E))
        
        lines.sort()
        
        ans = 0
        c = 0
        for t, flag in lines:
            if flag == S:
                c += 1
            else:
                c -= 1
            ans = max(ans, c)
        
        assert c == 0
        return ans

 

输出两组区间的交集

描述

目前有两个用户的有序在线时间序列,每一个区间记录了该用户的登录时间点x和离线时间点y,请找出这两个用户同时在线的时间段,输出的时间段请从小到大排序。

你需要返回一个intervals的列表

样例

样例 1:

输入:seqA = [(1,2),(5,100)], seqB = [(1,6)]
输出:[(1,2),(5,6)]
解释:在 (1,2), (5,6) 这两个时间段内,两个用户同时在线。

样例 2:

输入:seqA = [(1,2),(10,15)], seqB = [(3,5),(7,9)]
输出:[]
解释:不存在任何时间段,两个用户同时在线。

30行超简单扫描线算法,仍然是遇到start,count++,遇到end,count--,那么intersection就是找出所有时刻(x, x+1),其中x时刻count=2,x+1时刻的count=1

public class Solution {
    public List<Interval> timeIntersection(List<Interval> seqA, List<Interval> seqB) {
        seqA.addAll(seqB);
        List<Point> points = new ArrayList<>();
        for (Interval interval : seqA) {
            points.add(new Point(interval.start, true));
            points.add(new Point(interval.end, false));
        }

        Collections.sort(points, (p1, p2) -> p1.x - p2.x);

        int count = 0;
        int start = -1;
        List<Interval> res = new ArrayList<>();
        for (Point p : points) {
            if (p.ifStart) count++;
            else count--;

            if (count == 2) start = p.x;
            if (count == 1 && start != -1) {
                res.add(new Interval(start, p.x));
                start = -1;
            }
        }

        return res;
	}

    class Point {
        int x;
        boolean ifStart;
        public Point(int x, boolean ifStart) {
            this.x = x;
            this.ifStart = ifStart;
        }
    }
}

当然,还有双指针解法 ==>以前在没有学sweep line的时候我就是这样做的。。。

可以用二路归并相似的思路,用两个指针来分别记录两个list的当前扫描位置

然后分情况讨论

  1. 如果两个区间没有交集, seqAi.start > seqBj.end or seqAi.end < seqBj.start 在这种情况下就将end小的List的指针向前进一

  2. 如果两个区间有交集, 则统计 start 为两个start中大的那个, end 为两个end 中小的那个, 将这个区间放入答案集合, 并且前进end小的那个list的指针

因为两个list都是按start sorted并且没有Overlap, 所以结果也一定是按相同顺序排序 时间复杂度O(N) N为两个List中相对较短的长度, 空间复杂度 O(1)

class Solution:
    """
    @param seqA: the list of intervals
    @param seqB: the list of intervals
    @return: the time periods
    """
    def timeIntersection(self, seqA, seqB):
        # Write your code here
                
        if seqA == None or seqB == None or len(seqA) == None or len(seqB) == None:
            return []
            
        i,j = 0, 0
        ans = []
        while i < len(seqA) and j < len(seqB):
            if seqA[i].start > seqB[j].end:
                j += 1
                continue
            elif seqB[j].start > seqA[i].end:
                i += 1
                continue
            
            if seqA[i].start <= seqB[j].start:
                start = seqB[j].start
            elif seqA[i].start > seqB[j].start:
                start = seqA[i].start
            
            if seqA[i].end <= seqB[j].end:
                end = seqA[i].end
                i += 1
            elif seqA[i].end > seqB[j].end:
                end = seqB[j].end
                j += 1
            ans.append(Interval(start, end))
        return ans

 

posted @ 2021-02-14 22:34  bonelee  阅读(315)  评论(0编辑  收藏  举报