​welcome to my blog​

LeetCode Top 100 Liked Questions 253. Meeting Rooms II (Java版; Medium)

题目描述

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
//上车下车算法
class Solution {
public int minMeetingRooms(int[][] intervals) {
int n = intervals.length;
if(n<=1){
return n;
}
int[] left = new int[n];
int[] right = new int[n];
for(int i=0; i<n; i++){
left[i] = intervals[i][0];
right[i] = intervals[i][1];
}
Arrays.sort(left);
Arrays.sort(right);
int max = 1, cur=0;
int i=0, j=0;
while(i<n){
if(left[i] < right[j]){
cur++;
max = Math.max(max, cur);
i++;
}else if(left[i] > right[j]){
cur--;
j++;
}else{
i++;
j++;
}
}
return max;
}
}

第一次做; 维护一个小根堆, 小根堆的元素数量表示从开始到结束这个范围上重合的区间的最大值; 本质上就是求开始到结束范围上的重合区间数量最大值

//使用最小堆的元素个数表示重叠的区间数量; 压入结束时间; 如果当前的开始时间大于等于最小堆堆顶的结束时间, 说明有一个会议开完了, 弹出堆顶元素
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();
}
}

第一次做; 核心: 1) 把开始时间升序排序, 把结束时间升序排序; 2)遍历开始时间, 同时用endp指向第一个结束时间; 如果当前的开始时间小于结束时间, 表示需要一间会议室, res++; 如果当前的开始时间小于等于结束时间, 说明之前有一个会议结束了, res–, 当前这个会议又需要一间会议室, res++, 所以res不变, endp++; 实质上是找开始到结束范围上的重合区间数量

在脑子里过一遍下面这个例子

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++
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;
}
}

第一次做; 核心: 1)使用哈希表(TreeMap), key是时间, value是映射值, 具体地, 当key是开始时间时, 映射值++; 当key是结束时间时, 映射值–; 2)cur记录当前需要的房间数, res记录最终需要的房间数, 其实res就是cur所有值中的最大值 3)遍历TreeMap(会按照key的自然顺序排序, 本题中也就是按照时间从早到晚排序), cur = cur + 当前时间对应的映射值; 这道题实质上是找开始到结束范围上的重合区间数量

来看两个例子

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

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

LeetCode Top 100 Liked Questions 253. Meeting Rooms II (Java版; Medium)_leetcode

第二个例子: Input: [[7,10],[2,4]]
遍历TreeMap阶段如下图所示,
2处需要一间会议室, 此时共需要一间会议室
4处减少一间会议室, 此时不需要会议室
7处需要一间会议室, 此时共需要一间会议室
10处减少一间会议室, 此时不需要会议室

LeetCode Top 100 Liked Questions 253. Meeting Rooms II (Java版; Medium)_java_02

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);
map.put(arr[0], map.get(arr[0])+1);

if(!map.containsKey(arr[1]))
map.put(arr[1], 0);
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;
}
}