LeetCode 252. Meeting Rooms I && LeetCode 253. Meeting Rooms II

Meeting Rooms I (Easy) 题目

Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] (si < ei), determine if a person could attend all meetings.

Example 1:

Input: [[0,30],[5,10],[15,20]]
Output: false

Example 2:

Input: [[7,10],[2,4]]
Output: true

题目给了一系列时间数组,问这些数组之中有没有overlapping的,如果有就return false,否则return true。第一反应就是先按开始时间sort一遍,如果下一个的开始时间比上一个的结束时间早就return false,全部扫完没return false就return true。时间复杂度是排序的O(nlogn)

Runtime: 4 ms, faster than 96.12% of Java online submissions for Meeting Rooms.

Memory Usage: 38.7 MB, less than 99.15% of Java online submissions for Meeting Rooms.

class Solution {
    public boolean canAttendMeetings(int[][] intervals) {
        Arrays.sort(intervals, (a, b)-> a[0] - b[0]);
        for (int i = 1; i < intervals.length; i++) {
            if (intervals[i][0] < intervals[i - 1][1]) {
                return false;
            }
        }
        return true;
    }
}


Meeting Rooms II (Meduium) 题目

Given an array of meeting time intervals consisting of start and end times [[s1,e1],[s2,e2],...] (si < ei), find the minimum number of conference rooms required.

Example 1:

Input: [[0, 30],[5, 10],[15, 20]]
Output: 2

Example 2:

Input: [[7,10],[2,4]]
Output: 1

NOTE: input types have been changed on April 15, 2019. Please reset to default code definition to get new method signature.


这个是上一题的加强版,需要求出安排这样的会议一共要多少meeting rooms,依旧是没有思路看答案。首先一如既往的按照开始时间排序,排完以后我们可以看到,如果当前遍历到的这个会议的开始时间比所有meeting rooms里的结束时间要早,那就得新加一个room,如果相等或更晚(注意相等啊!),就可以占据之前那个meeting room。那么怎么得到最早结束的room的时间呢,就又是heap了。heap里只需要存放会议的结束时间即可,每次遍历的时候peek一下康康最早结束的room啥时候结束,然后相应地poll或者add就好了。时间复杂度O(nlogn),排序&heap插入都是吧。

Runtime: 7 ms, faster than 48.84% of Java online submissions for Meeting Rooms II.

Memory Usage: 39.1 MB, less than 86.96% of Java online submissions for Meeting Rooms II.

class Solution {
    public int minMeetingRooms(int[][] intervals) {
        if (intervals.length == 0) {
            return 0;
        }
        Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
        PriorityQueue<Integer> pq = new PriorityQueue<>();
        pq.add(intervals[0][1]);
        for (int i = 1; i < intervals.length; i++) {
            int lastEndTime = pq.peek();
            if (intervals[i][0] >= lastEndTime) {
                pq.poll();
            }
            pq.add(intervals[i][1]);
        }
        return pq.size();
    }
}

 另外一个解法非常巧妙,我们把开始和结束时间拆开来看,并不关心他们是不是针对一个会议,因为如果任意一个会议结束了,别的会议都可以使用这个房间,并不关心到底是谁结束了。于是,我们可以分别针对start和end进行排序,然后分别使用两个指针pStart和pEnd,如果pStart指向的会议开始时间比pEnd结束时间早,那么就得加一个room,否则就可以reuse这个room,并pEnd++开始看下一个结束时间。最后当然也要pStart++一下。太巧妙了,直接排序O(nlogn)+一次遍历O(n),总体还是O(nlogn)。

Runtime: 2 ms, faster than 96.95% of Java online submissions for Meeting Rooms II.

Memory Usage: 38.8 MB, less than 98.50% of Java online submissions for Meeting Rooms II.

class Solution {
    public int minMeetingRooms(int[][] intervals) {
        int len = intervals.length;
        int[] start = new int[len];
        int[] end = new int[len];
        for (int i = 0; i < intervals.length; i++) {
            start[i] = intervals[i][0];
            end[i] = intervals[i][1];
        }
        Arrays.sort(start);
        Arrays.sort(end);
        
        int pStart = 0;
        int pEnd = 0;
        int room = 0;
        while (pStart != len) {
            if (pStart == 0 || start[pStart] < end[pEnd]) {
                room++;
            } else {
                pEnd++;
            }
            pStart++;
        }
        
        return room;
    }
}

2024补充:

还有两个方法,感觉都像是line sweep扫描线算法的变种,有点prefixSum那味道。有两种实现方式,一个是数组,一个是TreeMap。

扫描线算法的核心思想在于我们只需要知道每个时间点上有没有meeting的增减。比如用数组的话就建一个可以cover所有时间长度的数组,第一个遍历每个interval以后,把开始时间对应的时间点++,结束时间对应的时间点--。这个时间数组其实就相当于是排序了,所以我们就可以遍历这个时间数组来计算到当前为止的meeting数量,和存放的max来对比看啥时候最大。

    public static int minMeetingRoomsPrefixSum(int[][] intervals) {
        int[] time = new int[10000];
        for (int[] interval : intervals) {
            time[interval[0]]++;
            time[interval[1]]--;
        }
        int result = 0;
        int prefixSum = 0;
        for (int i : time) {
            prefixSum += i;
            result = Math.max(result, prefixSum);
        }
        return result;
    }

TreeMap版本其实就是把数组换成TreeMap这样就不用开一个巨大的数组了,TreeMap也自带了排序功能所以就不需要额外再排序。

    public static int minMeetingRoomsTreeMap(int[][] intervals) {
        Map<Integer, Integer> map = new TreeMap<>();
        for (int[] interval : intervals) {
            map.put(interval[0], map.getOrDefault(interval[0], 0) + 1);
            map.put(interval[1], map.getOrDefault(interval[1], 0) - 1);
        }
        int result = 0;
        int prefixSum = 0;
        for (int i : map.values()) {
            prefixSum += i;
            result = Math.max(result, prefixSum);
        }
        return result;
    }

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值