1897 · 会议室 3(区间判重和最大重叠区间问题)

package com.heu.wsq.leetcode.interval;

import java.util.*;

/**
 * 1897 · 会议室 3
 * @author wsq
 * @date 2021/4/20
 * 描述
 * 你有一个当前会议列表intervals,里面表明了每个会议的开始和结束时间,以及一些会议室rooms。现在有一系列会议ask需要加入,逐个判断他们能否被安排进当前的会议列表中而不产生冲突。一个会议室在同一时间只能进行一场会议。每个询问都相互独立。
 * Ensure that Intervals can be arranged in rooms meeting rooms
 * Ensure that the end time of any meeting is not greater than 50000
 * |Intervals|<=50000
 * |ask|<=50000
 * rooms<=20
 *
 * 样例
 * 例 1:
 * 输入:
 *      Intervals:[[1,2],[4,5],[8,10]],rooms = 1,ask: [[2,3],[3,4]]
 * 输出:
 *      [true,true]
 *
 * 解释:
 *      对于[2,3]的询问,我们可以安排一个会议室room0。
 *      以下是room0的会议列表:
 *      [[1,2],[2,3],[4,5],[8,10]]
 *      对于[3,4]的询问,我们可以安排一个会议室room0。
 *      以下是room0的会议列表:
 *      [[1,2],[3,4],[4,5],[8,10]]
 *
 * 链接:https://www.lintcode.com/problem/1897/
 */
public class MeetingRoomIII {
    /**
     * 这道题太经典,主要是解决了区间判重以及最大重叠区间问题
     * 主要思路:
     * 1. 按开始时间和结束时间统计对应的数量
     * 2. 将两者merge到一起
     * 3. 按照时间升序排序
     * 4. 直接遍历merge后的列表获取重叠区间个数
     * 5. 其余子步骤看注释吧
     * @param intervals
     * @param rooms
     * @param ask
     * @return
     */
    public boolean[] meetingRoomIII(int[][] intervals, int rooms, int[][] ask) {
        // Write your code here.
        // 使用map保存,时间以及数量
        Map<Integer, Integer> map = new HashMap<>();
        for(int[] v: intervals){
            map.put(v[0], map.getOrDefault(v[0], 0) + 1);
            map.put(v[1], map.getOrDefault(v[1], 0) - 1);
        }
        // 将开始时间和结束时间归并到一起
        List<int[]> list = new ArrayList<>();
        for (Map.Entry<Integer, Integer> entry: map.entrySet()){
            list.add(new int[]{entry.getKey(), entry.getValue()});
        }
        // 按照时间升序排序list
        Collections.sort(list, new Comparator<int[]>(){
            public int compare(int[] o1, int[] o2){
                return o1[0] - o2[0];
            }
        });
        int preNum = 0;
        List<int[]> pos = new ArrayList<>();

        for(int i = 0; i < list.size(); i++){
            int[] v = list.get(i);
            preNum += v[1];
            // rooms一定是满足原来会议进行的
            if(preNum == rooms){
                // 证明当前会议用完了,所以保存 当前时间 到 下一个时间,
                // 这个时间段内没有会议室可用,也就是不能添加会议
                pos.add(new int[]{v[0], list.get(i + 1)[0]});
            }
        }

        boolean[] ans = new boolean[ask.length];
        if(pos.size() == 0){
            Arrays.fill(ans, true);
            return ans;
        }

        for(int i = 0; i < ask.length; i++){
            int idx = helper(pos, ask[i]);
            if(idx != pos.size() && pos.get(idx)[0] < ask[i][1]){
                ans[i] = false;
            }else if(idx != 0 && pos.get(idx - 1)[1] > ask[i][0]){
                ans[i] = false;
            }else{
                ans[i] = true;
            }
        }
        return ans;
    }

    /**
     * 使用二分查找 寻找到 pos.get(i)[1] 大于 one[0]
     * @param pos
     * @param one
     * @return
     */
    private int helper(List<int[]> pos, int[] one){
        int left = 0;
        int right = pos.size() - 1;
        while(left <= right){
            int mid = (left + right) >> 1;

            if(pos.get(mid)[1] > one[0]){
                right = mid - 1;
            } else {
                left = mid + 1;
            }
        }

        return left;
    }

    public static void main(String[] args) {
        int[][] intervals = {{1,2},{4,5},{8,10}};
        int rooms = 1;
        int[][] ask = {{2, 3}, {3, 4}};
        MeetingRoomIII meetingRoomIII = new MeetingRoomIII();
        boolean[] booleans = meetingRoomIII.meetingRoomIII(intervals, rooms, ask);
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值