253. Meeting Rooms II

Borris發表於2019-10-04

解法一:陣列排序

思路

將回憶間隔分為開始和結束兩個陣列,按照從小到大順序排序。要尋找一個會議開始時間是否和其他會議的最早結束時間衝突。
那麼,如果一個會議的開始時間在最早結束時間前開始,就需要一個房間,反之可以在其後面進行會議。如果一個會議開始時間大於最早結束時間,不需要額外房間,但最早的結束時間需要向後移動一個位置。
舉例:如 start = [1,3,5,15,35]; end = [9, 11, 26, 30, 33] 那麼1,3,5都在最早結束時間9的前面,所以都需要額外房間。此時房間數為3。15在9後面,所以不用額外安排時間,而最早結束時間變為11。35在11後面,所以也不用額外安排房間。所以總的房間數為3。

程式碼
class Solution {
    public int minMeetingRooms(int[][] intervals) {
        /*
        Sepearate the start and end to two arrays and sort them by ascending order
        Assign the earlist end time to be end[0];
        Initialize num of room = 0;
        for each start time
            if (start time > end time)
                earlist end time move to next end[];
            else
                num++
            end if 
        end for each
        */
        int len =  intervals.length;
        // 首先想到陣列為空的情況
        if (len == 0 || intervals == null) return 0;

        int[] start = new int[len];
        int[] end = new int[len];
        for (int i = 0; i < len; i++) {
            start[i] = intervals[i][0];
            end[i] = intervals[i][1];
        }
        Arrays.sort(start);
        Arrays.sort(end);
        int earlistIndex = 0;
        int num = 0;
        for (int i = 0; i < len; i++) {
            if (start[i] >= end[earlistIndex]) { // 要注意 edge case, 開始時間和結束時間相等也不用額外安排房間
                earlistIndex++;
            }
            else {
                num++;
            }
        }
        return num;
    }
}

時間複雜度:O(nlogn),因為排序花費O(nlogn),遍歷開始時間花費O(n)。
空間複雜度: O(n), 因為使用了兩個陣列去儲存時間。

解法二:MinHeap

思路

依然是將元素按開始時間排序,並比較之前會議的最早結束時間是否與當前會議的開始時間重合。
將陣列中元素按照開始時間從大到小排序;
定義一個PriorityQueue,按照結束時間從小到大儲存intervals;
從已經排序的陣列中取出間隔,如果開始時間和最早結束時間重合,存入PriorityQueue中;
否則,將最早結束時間擴散至當前會議的結束時間。

程式碼
class Solution {
    public int minMeetingRooms(int[][] intervals) {
        int len = intervals.length;
        if (len == 0 || intervals == null) {
             return 0;
        }
        Arrays.sort(intervals, new Comparator<int[]>(){
            public int compare(int[] a, int[]b) {
                return a[0] - b[0];
            }
        });

        PriorityQueue<int[]> minHeap  = new PriorityQueue<>(intervals.length, new Comparator<int[]>(){
            public int compare (int[] a, int[]b) {
                return a[1] - b[1];
            }
        });
        minHeap.offer(intervals[0]);
        // Start from the next element because the first one is already in the heap.
        for (int i = 1; i < len; i ++) {
            int[] earlistEnding = minHeap.poll();
            // No overlap, append the ending time
            if (intervals[i][0] >= earlistEnding[1]) {
                earlistEnding[1] = intervals[i][1];
            }
            // Overlap,  add a new room
            else
            {
                minHeap.offer(intervals[i]);
            }
            minHeap.offer(earlistEnding);
        }
        return minHeap.size();
    }
}

時間複雜度 O(nlogn), 空間複雜度 O(n)。

Takeaway

  • 注意空陣列情況和 edge cases。
  • PriorityQueue 的使用:
    • 建立:PriorityQueue<Integer> p = new PriorityQueue<>(); // 預設最小值在頭部
    • 使用:poll():彈出頭部的元素;offer():新增新的元素,按照規定的排序順序排列。
  • 自定義排序順序
    • Override (標準方法)
      • PriorityQueue<int[]> q = new PriorityQueue<>(size, new Comaprator<int[]>(){ public int new comapre(int[] a, int[] b){ return a[1] - b[1]; } });
    • lamda 表示式(簡化方法)PriorityQueue<int[]> q = new PriorityQueue<>(size, (int[] a, int[] b)->(a[1] - b[1]));
本作品採用《CC 協議》,轉載必須註明作者和本文連結

相關文章