1.題目介紹
題目地址(1353. 最多可以參加的會議數目 - 力扣(LeetCode))
https://leetcode.cn/problems/maximum-number-of-events-that-can-be-attended/
題目描述
給你一個陣列 events
,其中 events[i] = [startDayi, endDayi]
,表示會議 i
開始於 startDayi
,結束於 endDayi
。
你可以在滿足 startDayi <= d <= endDayi
中的任意一天 d
參加會議 i
。在任意一天 d
中只能參加一場會議。
請你返回你可以參加的 最大 會議數目。
示例 1:
輸入:events = [[1,2],[2,3],[3,4]] 輸出:3 解釋:你可以參加所有的三個會議。 安排會議的一種方案如上圖。 第 1 天參加第一個會議。 第 2 天參加第二個會議。 第 3 天參加第三個會議。
示例 2:
輸入:events= [[1,2],[2,3],[3,4],[1,2]] 輸出:4
提示:
1 <= events.length <= 105
events[i].length == 2
1 <= startDayi <= endDayi <= 105
2.題解
2.1 貪心演算法 + 優先順序佇列(小根堆)
思路
這裡我們思考最優貪心策略:
從左到右遍歷時間點i,某會議x在滿足起始時間startTime大於i(必要條件,否則無法參加),同時結束時間endTime是最早的(因為它結束時間最早,所以相比那些結束時間晚的更容易被淘汰,故優先選擇),每次都選擇這樣的會議參加或者該時間點沒有會議參加,區域性最優達成全域性最優。
那我們就要考慮進行實現了,首先要維護當前時間點i,可以參加的所有會議(並不是所有會議都開始了)
我們並不想維護一個長度為max_TimeEnd的vector陣列,並記錄其中所有可以參與的會議(這樣我們要遍歷max_TimeEnd次陣列,而且還要花費非常多的額外空間進行維護)
我們選擇使用優先順序佇列進行動態維護,噹噹前會議開始後,就將該會議加入到佇列中;噹噹前會議到達結束時間後/我們選擇參與了該會議,我們將該會議從佇列去除。
還有一個問題,我們該如何根據當前時間i,快速判斷有哪些會議開始,又有哪些會議結束呢?
如果使用原來的陣列,我們每次選擇都要從頭到尾遍歷一遍並進行判斷,這十分的耗費時間,
所以我們選擇使用一個雜湊表來維護:開始時間--結束時間的對映(這裡一個開始時間可能對應多個結束時間,比如像多個會議都是時間i開始,但結束時間不一樣,所以第二個引數是vector)
當我們得知當前時間後,就可以用mp.count(i)判斷是否有當前日期i開始的會議,並根據對映將mp[i]中儲存的結束時間加到優先順序佇列中,這樣就維護了進隊操作。
這裡我們使用一個基於小根堆的優先順序佇列,佇列儲存的是各個會議的結束時間,這樣就可以在選擇會議時讓結束時間早的會議優先出隊!
同時對於結束時間 < 當前時間的會議, 說明其已經結束了,不可能再進行選擇, 我們也要將其出隊。 這樣就維護了出隊操作
程式碼
- 語言支援:C++
C++ Code:
class Solution {
public:
int maxEvents(vector<vector<int>>& events) {
unordered_map<int, vector<int>> mp;
int cnt = 0;
int max_day = 0; // 用於記錄所有活動中最晚的結束時間,確定遍歷結束點
for(vector<int> event : events){
// 記錄開始時間和結束時間的對映,便於下文我們進行尋找
mp[event[0]].push_back(event[1]);
max_day = max(max_day, event[1]);
}
// 自底向上,將最早(小)結束的排在前面,所以greater(父節點 > 子節點的值就交換,將大的值沉底)
priority_queue<int, vector<int>, greater<int>> q;
// 從左到右遍歷每一天,看每一天是否有會議可以參加
for(int i = 0; i <= max_day; i++){
// 如果有今天開始的會議,加入優先順序佇列
if(mp.count(i)){
for(int endTime : mp[i]){
q.push(endTime);
}
}
// 去除在今天i已經結束的佇列成員
while(!q.empty() && q.top() < i){
q.pop();
}
// 選擇一個結束最早的會議參加
if(!q.empty()){
cnt++;
q.pop();
}
}
return cnt;
}
};
複雜度分析
令 n 為陣列長度。
- 時間複雜度:\(O(n)\)
- 空間複雜度:\(O(n)\)