首页 > 其他分享 >23-05-20 总结 Meeting rooms 系列3个题目

23-05-20 总结 Meeting rooms 系列3个题目

时间:2023-05-20 10:34:54浏览次数:52  
标签:sort 20 23 int 05 PriorityQueue time minHeap meeting

题目列表:

P1. 会员题,检测会议是否安排得开

image-20230519231416595

思路:

  • 非常简单,直接按start time进行排序,然后检测是否有overlap即可
  • 时间:O(nlog n),空间:O(1)
class Solution {
    public boolean canAttendMeetings(int[][] A) {
        if (A.length == 0) return true;
        // just sort the array according to start time
        Arrays.sort(A, (a, b) -> Integer.compare(a[0], b[0]));
        int prevEnd = -1;
        for (int[] meeting : A) {
            if (meeting[0] < prevEnd) {
                return false;
            }
            prevEnd = meeting[1];
        }
        return true;
    }
}

P2 求需要多少间会议室

image-20230519231744617

解法1:优先队列 - O(n logn)

思路:

  • 之前做过,这个直接模拟真实场景的会议室安排算法。对会议的开始时间升序排列,开始时间相同的,按照结束时间升序排列。依次分配会议室,同时维护一个已分配的会议室列表,对于第i个会议,在给它分配会议室前,看之前是否有会议结束了。如果有会议在它之前结束,那就不需要再分配新会议室。没有,则需要分配一间新会议室。在这个过程中,维护的当前的会议室列表,最大长度就是所需要的会议室的数量。

  • 那么怎么知道当前会议,在此之前,是否有会议结束呢?直观的做法是维护一个会议室的列表,按结束时间排序,如果最前面的会议室,它的结束时间小于当前的会议开始时间,则意味着有空闲的会议室了。为了快速找到一个列表中,最小的元素,我们可以使用小根堆来做,java中使用PriorityQueue类。

  • 复杂度分析:

    • 时间:O(n log n). 排序所有会议,O(nlogn), 优先队列保存在线的会议,每个会议进入队列一次,出去一次,所以时间复杂度是O(nlogn)
    • 空间:O(n). 使用了优先队列,最多保存n个元素,O(n)。
class Solution {
    public int minMeetingRooms(int[][] A) {
        Arrays.sort(A, (a, b) -> {
            if (a[0] != b[0]) {
                return Integer.compare(a[0], b[0]);
            }
            return Integer.compare(a[1], b[1]);
        });
        // store the end time of meeting which were assigned meeting room
        PriorityQueue<Integer> minHeap = new PriorityQueue<>();
        int ans = 0;
        for(int[] meeting : A) {
            // check if there is any meeting room available
            while (!minHeap.isEmpty() && minHeap.peek() <= meeting[0]) {
                minHeap.poll();
            }
            // assign a meeting room either new or reuse old one
            minHeap.offer(meeting[1]);
            // update the maximum live meeting room number
            ans = Math.max(ans, minHeap.size());
        }
        return ans;
    }
}

好像不用针对end time进行排序也可以,只按照start time排序,不知道是否是test case miss。需要再此思考一下,想清楚。【TODO】

class Solution {
    public int minMeetingRooms(int[][] A) {
        Arrays.sort(A, (a, b) -> Integer.compare(a[0], b[0]));
        // store the end time of meeting which were assigned meeting room
        PriorityQueue<Integer> minHeap = new PriorityQueue<>();
        int ans = 0;
        for(int[] meeting : A) {
            // check if there is any meeting room available
            while (!minHeap.isEmpty() && minHeap.peek() <= meeting[0]) {
                minHeap.poll();
            }
            // assign a meeting room either new or reuse old one
            minHeap.offer(meeting[1]);
            // update the maximum live meeting room number
            ans = Math.max(ans, minHeap.size());
        }
        return ans;
    }
}

看了题解,更好的做法是,在考虑第i个会议时,不需要把所有的结束的会议都清理掉,只看最早结束的一个就可以了,然后最后剩下的队列大小就是会议室的个数。【best】

class Solution {
    public int minMeetingRooms(int[][] A) {
        Arrays.sort(A, (a, b) -> Integer.compare(a[0], b[0]));
        // store the end time of meeting which were assigned meeting room
        PriorityQueue<Integer> minHeap = new PriorityQueue<>();
        for(int[] meeting : A) {
            // check if there is any meeting room available
            if (!minHeap.isEmpty() && minHeap.peek() <= meeting[0]) {
                minHeap.poll();
            }
            // assign a meeting room either new or reuse old one
            minHeap.offer(meeting[1]);
        }
        return minHeap.size();
    }
}

实现细节:for循环里,也可以使用index-based, 先把第一个会议的结束时间加到minHeap,然后再遍历剩下的n-1个会议。

思考:这题是否可以使用Sweep line思路来做?可以,但是需要特别注意排序points的顺序。

解法2: SweepLine - O(n logn)

class Solution {
    public int minMeetingRooms(int[][] A) {
        int n = A.length;
        int[][] points = new int[2*n][2];
        // Sweep line
        for(int i = 0, j = 0; i < n; i++, j++) {
            points[j][0] = A[i][0];
            points[j][1] = -1; // start point
            points[++j][0] = A[i][1];
            points[j][1] = 1; // end point;
        }
        // sort according to time
        Arrays.sort(points, (a, b) -> { // 这里的排序很关键
            if (a[0] != b[0]) return Integer.compare(a[0], b[0]);
            return Integer.compare(b[1], a[1]);
        });

        // check each time point
        int count = 0, ans = 0;
        for(int[] point : points) {
            if (point[1] == -1) {
                count++;
            } else {
                count--;
            }
            ans = Math.max(ans, count);
        }

        return ans;
    }
}

排序很关键,如果只按time排序,那么案例:[[13,15],[1,13]]会返回2,正确答案是1。然后如果时间相同,先按照start,再按end,上述案例同样返回2。正确的是先按时间升序排列,然后按照结束、开始排列。一个会议结束了,count-1,下一个会议就可以利用这个会议室了。

复杂度分析:

  • 时间:O(nlogn) 总共是2n个point,排序O(nlogn),后面遍历每个点,O(n)
  • 空间:O(n)

P3 III. 求预定最多的会议室

题目描述:LeetCode - The World's Leading Online Programming Learning Platform

我的第一个版本:思路:

  • use a minHeap to track the end time of live meeting (also need to store the roomId)
  • use a TreeSet to track the available meeting rooms, and we use small index first, so it needs to be sorted. And support getting minValue, and insert operation. 【思考:这里是否也可以使用PriorityQueue? 我看讨论区有提到两个PQ,可以!】
class Solution {
    public int mostBooked(int n, int[][] meetings) {
        // sort meetings according to start time, simulate real meeting arrangement
        Arrays.sort(meetings, (a, b) -> Integer.compare(a[0], b[0]));
        
        // track available meeting rooms
        TreeSet<Integer> availableRooms = new TreeSet<>();
        int[] bookCounts = new int[n];
        for(int i = 0; i < n; i++) {
            availableRooms.add(i);
        }

        // track the end time of each live meetings (endTime, roomIdx)
        PriorityQueue<long[]> minHeap = new PriorityQueue<>((a, b) -> {
            if (a[0] != b[0]) return Long.compare(a[0], b[0]); // sort by end time asc
            return Long.compare(a[1], b[1]); // sort by roomIdx asc
        });

        // arrangement
        for(int[] meeting : meetings) {
            long start = meeting[0], end = meeting[1];
            // check if there is any meeting ending
            while (!minHeap.isEmpty() && minHeap.peek()[0] <= start) {
                int roomId = (int)minHeap.poll()[1];
                availableRooms.add(roomId);
            }
            // delay meeting, until first meeting room available (i.e. end time shortest)
            if (availableRooms.isEmpty()) {
                long[] cur = minHeap.poll();
                availableRooms.add((int)cur[1]);
                // delay the meeting
                end = (end - start) + cur[0];
                start = cur[0];
            }
            
            int roomId = availableRooms.first();
            availableRooms.remove(roomId);
            bookCounts[roomId]++;
            minHeap.offer(new long[] {end, roomId});
        }
        // find most booked meeting room
        int ans = 0;
        for(int i = 1; i < n; i++) {
            if (bookCounts[i] > bookCounts[ans]) {
                ans = i;
            }
        }
        return ans;
    }
}

复杂度分析:

  • 时间: O(n + m logn). m个meeting。track meeting room book count, O(n). first sort meetings according to start time, which is O(m logm), each meeting will enter the pq only once, and poll once, each offer/poll operation of heap is O(log n), the heap at most contains n items. The total time is O(n + m logn)
  • 空间:O(n). use array to track room booked count: O(n), use minHeap to track meeting end time, at most n meetings be held at same time, so heap max size is O(n).

版本2:小改动,使用两个PriorityQueue,替换了上面版本1的TreeSet,操作稍微简化了一点点 (TreeSet.first() + remove(x),直接用pq.poll()即可)

class Solution {
    public int mostBooked(int n, int[][] meetings) {
        // sort meetings according to start time, simulate real meeting arrangement
        Arrays.sort(meetings, (a, b) -> Integer.compare(a[0], b[0]));
        
        // track available meeting rooms
        PriorityQueue<Integer> availableRooms = new PriorityQueue<>();
        int[] bookCounts = new int[n];
        for(int i = 0; i < n; i++) {
            availableRooms.offer(i);
        }

        // track the end time of each live meetings (endTime, roomIdx)
        PriorityQueue<long[]> minHeap = new PriorityQueue<>((a, b) -> {
            if (a[0] != b[0]) return Long.compare(a[0], b[0]); // sort by end time asc
            return Long.compare(a[1], b[1]); // sort by roomIdx asc
        });

        // arrangement
        for(int[] meeting : meetings) {
            long start = meeting[0], end = meeting[1];
            // check if there is any meeting ending
            while (!minHeap.isEmpty() && minHeap.peek()[0] <= start) {
                int roomId = (int)minHeap.poll()[1];
                availableRooms.offer(roomId);
            }
            // delay meeting, until first meeting room available (i.e. end time shortest)
            if (availableRooms.isEmpty()) {
                long[] cur = minHeap.poll();
                availableRooms.offer((int)cur[1]);
                // delay the meeting
                end = (end - start) + cur[0];
                start = cur[0];
            }
            
            int roomId = availableRooms.poll();
            bookCounts[roomId]++;
            minHeap.offer(new long[] {end, roomId});
        }
        // find most booked meeting room
        int ans = 0;
        for(int i = 1; i < n; i++) {
            if (bookCounts[i] > bookCounts[ans]) {
                ans = i;
            }
        }
        return ans;
    }
}

时间复杂度分析几乎不变,因为PQ的每次操作时间复杂度也是O(log n),最多有n个room空闲。最多offer操作n+m次。

标签:sort,20,23,int,05,PriorityQueue,time,minHeap,meeting
From: https://www.cnblogs.com/xianzhon/p/17416861.html

相关文章

  • CSP-J2021试题题解
    1.分糖果原题:https://www.luogu.com.cn/problem/P7909原代码:#include<bits/stdc++.h>#definelllonglongusingnamespacestd;lln,l,r;intmain(){ cin>>n>>l>>r; if(r%n==n-1)cout<<n-1; elseif(l%n==n-1)cout<<n-1; elseif(......
  • 2023/5/20
    %%订阅IMU话题四元数数据1.创建订阅者 订阅imu话题,消息格式:sensor_msgs/Imusensor_msgs/Imu消息格式:订阅者:ros::Subscriberimu_sub=n.subscribe("/imu/data",10,imucallback);2.imucallback回调函数处理四元数解算机器人方向2.1声明个四元数对象并赋值:tf::Quaternion......
  • 【BSP视频教程】BSP视频教程第26期:CAN/CANFD/CANopen专题,CANFD整个运行机制精讲,图文并
     上期视频教程为大家分享了很多CAN理论方面的知识,本期视频教程我们在实战应用中学习CANFD。CANFD涉及到的知识点非常多,我们本期重点是把CANFD整个运行机制搞明白,知其然知其所以然。视频:https://www.bilibili.com/video/BV1iX4y117Bv视频提纲:参考资料:1、【原创】H7-TOOL的CANFDT......
  • 【BSP视频教程】BSP视频教程第26期:CAN/CANFD/CANopen专题,CANFD整个运行机制精讲,图文并
     上期视频教程为大家分享了很多CAN理论方面的知识,本期视频教程我们在实战应用中学习CANFD。CANFD涉及到的知识点非常多,我们本期重点是把CANFD整个运行机制搞明白,知其然知其所以然。视频:https://www.bilibili.com/video/BV1iX4y117Bv视频提纲:参考资料:1、【原创】H7-TOOL的CANFDT......
  • 【爬虫数据集】李子柒YouTube频道TOP10热门视频的TOP2000热门评论,共计2W条
    目录一、背景二、爬取目标三、结果展示四、演示视频五、附完整数据一、背景这段时间,有超多小伙伴找我要YouTube数据,做数据分析、情感分析之类的研究工作,但很多人并不是计算机软件相关专业,不具备爬虫开发技术,但又有数据需求,可能是新闻传播学、社会学等相关学科,旨在分析社会热点现......
  • 常用的标准LCD驱动芯片,性价比高,稳定性好,多种封装型号选择VK1056
    型号:VK1056BVK1056C品牌:永嘉微电/VINKA封装形式:SOP24SSOP24年份:最新年份VK1056B/C概述:VK1056B/C是56点、内存映象和多功能的LCD驱动,VK1056B的软件配置特性使它适用于多种LCD应用场合,包括LCD模块和显示系统,用于连接主控制器和VK1056B的管脚只有4条,VK1056B......
  • 洛谷 P9248 - [集训队互测 2018] 完美的集合
    显然,如果选择的\(k\)个“合法集合”固定了,那么可以放置装置的点如果存在,那么必然形成一个连通块,也就是说,答案等于所有合法方案中,可以放置装置的点形成的连通块个数之和。而根据点减边的套路,这等价于,枚举每个点,计算有多少种方案满足可以在其放置装置,再枚举每条边,计算有多少种方案......
  • 【做题记录】SHOI 2012 魔法树
    有两个操作:将\(u\)到\(v\)路径增加\(k\)询问\(u\)节点的子树和显然,我们可以用树链剖分+线段树来做。代码:#include<cstdlib>#include<cstdio>#include<cctype>#include<algorithm>typedeflonglongLL;typedefunsignedlonglongULL;namespaceFastIo{......
  • 2023-05-19:汽车从起点出发驶向目的地,该目的地位于出发位置东面 target 英里处。 沿途
    2023-05-19:汽车从起点出发驶向目的地,该目的地位于出发位置东面target英里处。沿途有加油站,每个station[i]代表一个加油站,它位于出发位置东面station[i][0]英里处,并且有station[i][1]升汽油。假设汽车油箱的容量是无限的,其中最初有startFuel升燃料。它每行驶1英里......
  • 2023/5/19
    L1-031到底是不是太胖了分数 10全屏浏览题目作者 陈越单位 浙江大学据说一个人的标准体重应该是其身高(单位:厘米)减去100、再乘以0.9所得到的公斤数。真实体重与标准体重误差在10%以内都是完美身材(即|真实体重 − 标准体重| < 标准体重×10%)。......