【NO.71】LeetCode HOT 100— 253. 会议室 II

本文介绍了如何使用小顶堆、上车下车方法以及哈希表解决会议室II问题,即给定会议时间区间,计算最少需要多少会议室。通过比较开始时间和结束时间,确保在每个区间结束时更新会议室需求。
摘要由CSDN通过智能技术生成

253. 会议室 II

给你一个会议时间安排的数组 intervals ,每个会议时间都会包括开始和结束的时间 intervals[i] = [starti, endi] ,返回 所需会议室的最小数量 。

示例 1:
输入:intervals = [[0,30],[5,10],[15,20]]
输出:2

示例 2:
输入:intervals = [[7,10],[2,4]]
输出:1

提示:
1 <= intervals.length <= 104
0 <= starti < endi <= 106

解题

此题本质上还是比较一个会议的结束时间 和 下一个会议的开始时间的关系,如果结束时间大于开始时间,则需要的会议室数就加1。所以我们需要先按开始时间排序,然后遍历,比较结束时间与开始时间

方法一:利用小顶堆

小根堆的元素数量表示从开始到结束这个范围上重合的区间的最大值; 本质上就是求开始到结束范围上的重合区间数量最大值。
思路:先把数组按照开始时间升序,然后使用最小堆的元素个数表示重叠的区间数量; 堆中压入结束时间; 如果当前的开始时间大于等于最小堆堆顶的结束时间, 说明有一个会议开完了, 弹出堆顶元素

class Solution {
    public int minMeetingRooms(int[][] intervals) {
        //对数组按照开始时间升序排序
        Arrays.sort(intervals, (a,b)->a[0]-b[0]);
        
        //最小堆中存放结束时间; 最小堆中的元素数量表示从开始到结束重合的区间数量的最大值
        PriorityQueue<Integer> minHeap = new PriorityQueue<>();
        for(int i=0; i<intervals.length; i++){
            //如果最小堆不为空,并且当前时间段的开始时间大于等于堆顶元素, 说明之前有个会议结束了, 弹出该堆顶元素, 表示会议室数量减一
            if(!minHeap.isEmpty() && intervals[i][0]>=minHeap.peek()) {
				minHeap.poll();
			}   
            minHeap.add(intervals[i][1]);
        }
        return minHeap.size();
    }
}

方法二:上车下车方法

将开始时间、结束时间分别存放进两个数组,把开始时间升序排序, 把结束时间升序排序;

遍历开始时间, 同时用endp指向第一个结束时间;

  • 如果当前的开始时间小于结束时间, 表示需要一间会议室, res++;
  • 如果当前的开始时间大于等于结束时间, 说明之前有一个会议结束了, res–, 当前这个会议又需要一间会议室, res++, 所以res不变, endp++;

实质上是找开始到结束范围上的重合区间数量

class Solution {
    public int minMeetingRooms(int[][] intervals) {
        int n = intervals.length;
        int[] starts = new int[n];
        int[] ends = new int[n];
        for(int i=0; i<n; i++){
            starts[i] = intervals[i][0];
            ends[i] = intervals[i][1];
        }
        Arrays.sort(starts);
        Arrays.sort(ends);
        // 找出最多几个区间重合
        int res = 0;
        int endp = 0;
        for(int i=0; i<n; i++){
            //如果开始时间小于ends[endp]说明需要一间会议室
            if(starts[i] < ends[endp])
                res++; 
            else{
                //说明之前有个会议结束了, 使用的会议室数量减一, 
                //同时当前这个时间又开始了一个会议, 使用的会议室数量加一; 
                // 相当于使用的会议室数量不变
                // res--;
                // res++;
                endp++;
            }
        }
        return res;
    }
}

例子:

input: [[26,29],[19,26],[19,28],[4,19],[4,25]]
对开始时间排序:starts=[4,4,19,19,26]
对结束时间排序:ends=[19,25,26,28,29]
初始化res=0, endp=0
具体地遍历过程
strats[0] < ends[0],   res++
strats[1] < ends[0],   res++
strats[2] >= ends[0],  res--, res++, endp++
strats[3] < ends[1],   res++
strats[4] >= ends[1],  res--,res++, endp++

方法三:使用哈希表

使用哈希表(TreeMap), key是时间, value是映射值(需要会议室的数量),

  • 具体地, 当key是开始时间时, 映射值++;
  • 当key是结束时间时, 映射值–;

cur记录当前需要的房间数, res记录最终需要的房间数, 其实res就是cur所有值中的最大值

遍历TreeMap(会按照key的自然顺序排序, 本题中也就是按照时间从早到晚排序), cur = cur + 当前时间对应的映射值; 这道题实质上是找开始到结束范围上的重合区间数量

class Solution {
    public int minMeetingRooms(int[][] intervals) {
        //TreeMap按照自然顺序排序, 对于int来说就是从小到大排序
        TreeMap<Integer, Integer> map = new TreeMap<>();
        for(int[] arr : intervals){
            if(!map.containsKey(arr[0])) {
				map.put(arr[0], 0);
			} else {
				map.put(arr[0], map.get(arr[0])+1);
			}
                
            if(!map.containsKey(arr[1])) {
				map.put(arr[1], 0);
			} else {
				 map.put(arr[1], map.get(arr[1])-1);
			}
        }
        //记录当前需要的房间数
        int cur = 0;
        //记录最终的结果
        int res = 0;
        //遍历TreeMap
        for(Map.Entry<Integer, Integer> e : map.entrySet()){
            int key = e.getKey();
            int val = e.getValue();
            //
            cur = cur + val;
            res = Math.max(res, cur);
        }
        return res;
    }
}

例子:

第一个例子: Input: [[0, 30],[5, 10],[15, 20]]
遍历TreeMap阶段如下图所示, 
0处需要一间会议室, 
5处又需要一间会议室, 此时我们需要两间会议室; 
10处会减少一间会议室, 也就是只需要一间会议室了, 
15处需要一间会议室, 此时我们需要两间会议室; 
20处减少一间会议室, 此时我们需要一间会议室
30处减少一间会议室, 此时我们需要一间会议室

上述过程中, 我们最多需要两间会议室

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

悬浮海

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值