🚩传送门:牛客题目

题目

[NC]147. 主持人调度 - 图1个活动即将举办,每个活动都有开始时间与活动的结束时间,第 [NC]147. 主持人调度 - 图2个活动的开始时间是 [NC]147. 主持人调度 - 图3,第[NC]147. 主持人调度 - 图4个活动的结束时间是 [NC]147. 主持人调度 - 图5 ,举办某个活动就需要为该活动准备一个活动主持人。

一位活动主持人在同一时间只能参与一个活动。并且活动主持人需要全程参与活动,换句话说,一个主持人参与了第[NC]147. 主持人调度 - 图6个活动,那么该主持人在 ( [NC]147. 主持人调度 - 图7) 这个时间段不能参与其他任何活动。求为了成功举办这[NC]147. 主持人调度 - 图8个活动,最少需要多少名主持人。

数据范围: [NC]147. 主持人调度 - 图9[NC]147. 主持人调度 - 图10
复杂度要求:时间复杂度 [NC]147. 主持人调度 - 图11 ,空间复杂度 [NC]147. 主持人调度 - 图12

示例1

输入:2,[[1,3],[2,4]] 返回值:2

解题思路:贪心

首先,要对活动进行排序:

  • 开始时间相等的,结束时间从小到大
  • 开始时间不相等的,开始时间从小到大
    1. int[][] startEnd = new int[][]{{1,2},{2,5},{2,3}};
    2. Arrays.sort(startEnd,new Comparator<int[]>(){
    3. public int compare(int[] arr1,int[] arr2){
    4. if(arr1[0] == arr2[0]){
    5. return arr1[1] - arr2[1];
    6. }
    7. return arr1[0] - arr2[0];
    8. }
    9. });
    1. int[][] startEnd = new int[][]{{1,2},{2,5},{2,3}};
    2. Arrays.sort(startEnd,(o1,o2)->{
    3. return o1[0]==o2[0]?o1[1]-o2[1]:o1[0]-o2[0];
    4. });
    但是这个会有问题,对于负数,**整数-负数**得到1,导致也会交换,负数被扔到了后面
    image.png
    因此先判断正负再排序
    1. Arrays.sort(startEnd,(o1,o2)->{
    2. if(o1[0] > 0 && o2[0] < 0) return 1;
    3. if(o1[0] < 0 && o2[0] > 0) return -1;
    4. return o1[0]==o2[0]?o1[1]-o2[1]:o1[0]-o2[0];
    5. });
    image.png
    得到了有序活动时间后,我们可以使用线程池的思想,每遇到一场活动,我们就跟分配内存一样,去主持人池子里查找一下,有没有空闲的主持人将他分配给这个活动,当所有主持人都有活动的时候,在重新开辟一个新的主持人出来主持新的活动 。

复杂度分析

时间复杂度:[NC]147. 主持人调度 - 图15,其中 [NC]147. 主持人调度 - 图16 是主持人个数, [NC]147. 主持人调度 - 图17 是活动场数。

空间复杂度:[NC]147. 主持人调度 - 图18,其 [NC]147. 主持人调度 - 图19 是活动场数。

我的代码

  1. public class Solution {
  2. public boolean checkPerSon(int[]ans,int startTime,int endTime){
  3. // 主持人线程池
  4. for(int i=1;i<=ans[0];i++){
  5. // 当前是否有主持人空闲
  6. if(ans[i]<=startTime){
  7. ans[i]=endTime;
  8. return true;
  9. }
  10. }
  11. ans[0]++; // 新增一个主持人
  12. ans[ans[0]]=endTime; // 记录新增主持人的结束时间
  13. return false;
  14. }
  15. public int minmumNumberOfHost (int n, int[][] startEnd) {
  16. // write code here
  17. if(startEnd==null) return 0;
  18. if(startEnd.length==1) return 1;
  19. Arrays.sort(startEnd,(o1,o2)->{
  20. if(o1[0] > 0 && o2[0] < 0) return 1;
  21. if(o1[0] < 0 && o2[0] > 0) return -1;
  22. return o1[0]==o2[0]?o1[1]-o2[1]:o1[0]-o2[0];
  23. });
  24. // 主持人池子
  25. int[] ans=new int[startEnd.length+1];
  26. ans[0]=1; // 0 位标志位,存储主持人个数
  27. ans[1]=startEnd[0][1]; // 记录第一场结束时间
  28. // 遍历所有的活动
  29. for(int i=1;i<startEnd.length;i++){
  30. // 调用checkPerSon检查分配空余主持人
  31. checkPerSon(ans,startEnd[i][0],startEnd[i][1]);
  32. }
  33. return ans[0];
  34. }
  35. }

这个复杂度显然是不满足时间复杂度 [NC]147. 主持人调度 - 图20空间复杂度 [NC]147. 主持人调度 - 图21

因此我们可以利用优先队列(堆)来进行优化,每次自动吐出一个结束时间最早的主持人出来,让他主持新的活动,每次调整一个新的主持人时间复杂度是[NC]147. 主持人调度 - 图22,一共吐出 [NC]147. 主持人调度 - 图23个活动主持人,因此总的时间复杂度是[NC]147. 主持人调度 - 图24

🚩我的代码 [ 优先队列 ]

  1. public class Solution {
  2. public int minmumNumberOfHost (int n, int[][] startEnd) {
  3. // write code here
  4. if(startEnd==null) return 0;
  5. if(startEnd.length==1) return 1;
  6. Arrays.sort(startEnd,(o1,o2)->{
  7. if(o1[0] > 0 && o2[0] < 0) return 1;
  8. if(o1[0] < 0 && o2[0] > 0) return -1;
  9. return o1[0]==o2[0]?o1[1]-o2[1]:o1[0]-o2[0];
  10. });
  11. PriorityQueue<Integer> pQueue =new PriorityQueue<>();
  12. pQueue.add(Integer.MIN_VALUE);
  13. for(int i=0;i<startEnd.length;i++){
  14. if(pQueue.peek()<=startEnd[i][0]){ // 有空闲的主持人
  15. pQueue.poll(); // 将该主持人出队,出去更换新的活动信息
  16. }
  17. pQueue.offer(startEnd[i][1]); // 插入新的活动信息的主持人
  18. }
  19. return pQueue.size();
  20. }
  21. }