掃描線專題
leetcode 陣列專題 06-掃描線演算法(Sweep Line Algorithm)
leetcode 陣列專題 06-leetcode.218 the-skyline-problem 力扣.218 天際線問題
leetcode 陣列專題 06-leetcode.252 meeting room 力扣.252 會議室
leetcode 陣列專題 06-leetcode.253 meeting room ii 力扣.253 會議室 II
什麼是掃描線演算法?
掃描線演算法(Sweep Line Algorithm)是一種常用於解決幾何問題(尤其是涉及區間、時間線或事件的重疊問題)的演算法。
它的基本思想是“模擬一條掃描線從一個方向掃過所有事件”,在掃描過程中維護一個資料結構來追蹤當前的狀態(例如活動區間的數量、最小值、最大值等)。
掃描線演算法的基本步驟
-
事件表示:每個問題中的區間(例如會議時間)或事件,都可以轉化為若干個關鍵事件(例如開始時間和結束時間)。
-
事件排序:將所有事件按照時間排序(如果時間相同,則根據事件的型別來排序,例如結束事件優先於開始事件)。
-
掃描過程:從最早的事件開始,按照排序順序逐一處理每個事件,並在處理每個事件時更新狀態(例如活動會議的數量、最大活動時間等)。
-
資料維護:根據事件型別,更新當前的活動狀態。例如,遇到一個開始事件時,我們增加一個計數,遇到結束事件時,減少計數,或者更新其他需要維護的值。
-
輸出結果:在掃描過程中,根據需求輸出解答。
應用場景
掃描線演算法廣泛應用於處理各種區間問題,典型的應用包括:
- 會議安排(檢測會議時間是否有重疊)
- 區間覆蓋問題(檢查是否有足夠的資源覆蓋所有區間)
- 計算最大併發數(計算在某一時間點活躍的事件數量,如計算最多同時存在的會議數)
- 凸包問題(計算一個點集的最小凸包)
掃描線演算法的具體步驟
1. 事件表示與排序
假設我們有若干個區間(如會議的開始時間和結束時間),我們首先將每個區間拆解為兩個事件:
一個是開始事件,另一個是結束事件。
每個事件可以表示為一個元組 (time, type)
,其中 time
表示事件發生的時間,type
可以是 +1
(表示開始)或者 -1
(表示結束)。
例如,會議區間 [(5, 10), (8, 12), (13, 16)]
可以拆解為事件:
[(5, +1), (10, -1), (8, +1), (12, -1), (13, +1), (16, -1)]
事件按時間排序。如果有多個事件發生在相同的時間點,則優先處理結束事件,因為結束事件可以使得下一個開始事件得以處理。
2. 事件掃描與狀態更新
掃描線的核心是對事件的處理。在掃描線遍歷時,我們保持一個計數器(或其他資料結構)來跟蹤當前的活動狀態。對於會議安排問題,我們使用一個計數器來記錄當前同時進行的會議數量。
- 當遇到一個 開始事件(
+1
),增加計數器,表示新的會議開始。 - 當遇到一個 結束事件(
-1
),減少計數器,表示一個會議結束。
3. 結果輸出
在掃描過程中,我們可以輸出每個時間點的活動狀態。例如,我們可以在每次更新計數器時,檢查當前同時進行的會議數,或者記錄最大會議數等。
例子:檢測會議是否有重疊
假設我們有一組會議的時間區間,使用掃描線演算法來判斷是否所有會議都能參加。
給定的會議區間:[[0, 30], [5, 10], [15, 20]]
1. 拆解事件
我們將每個會議區間拆解成開始事件和結束事件:
[(0, +1), (30, -1), (5, +1), (10, -1), (15, +1), (20, -1)]
2. 事件排序
按時間排序事件,時間相同的情況下優先處理結束事件:
[(0, +1), (5, +1), (10, -1), (15, +1), (20, -1), (30, -1)]
3. 掃描事件並更新狀態
我們從第一個事件開始,逐一掃描:
- 在時間
0
處,遇到開始事件+1
,活動會議數增加到 1。 - 在時間
5
處,遇到開始事件+1
,活動會議數增加到 2,說明此時有兩個會議重疊。 - 在時間
10
處,遇到結束事件-1
,活動會議數減少到 1。 - 在時間
15
處,遇到開始事件+1
,活動會議數增加到 2,說明此時又有兩個會議重疊。 - 在時間
20
處,遇到結束事件-1
,活動會議數減少到 1。 - 在時間
30
處,遇到結束事件-1
,活動會議數減少到 0。
4. 判斷是否有重疊
在掃描過程中,我們發現活動會議數有過大於 1 的情況(特別是在時間 5
和時間 15
),因此有重疊會議,返回 false
。
掃描線演算法的優勢
-
時間複雜度:事件排序的時間複雜度是
O(n log n)
,其中n
是會議數或事件數。掃描線的遍歷時間複雜度是O(n)
。因此,整體時間複雜度是O(n log n)
,比暴力演算法(O(n^2)
)要高效得多。 -
空間複雜度:需要儲存所有事件,空間複雜度為
O(n)
。 -
易於擴充套件:掃描線演算法可以很容易地適應更多的需求,例如統計某一時刻活動的最大數量、求得活動的區間並進行其他計算等。
擴充套件應用
- 最大併發活動數:透過掃描線演算法,我們可以輕鬆地計算在某個時刻同時進行的最多會議數(即最大併發數)。
- 區間合併:我們還可以透過掃描線演算法來合併重疊的區間。
- 區間覆蓋:檢查一組區間是否能完全覆蓋一個目標區間等。
總結
掃描線演算法是一種非常強大且高效的演算法,尤其適用於處理與區間重疊、事件排序相關的幾何問題。
在許多情況下,它比暴力演算法要高效得多,尤其是在資料量大的時候,能夠顯著減少計算的複雜度。
參考資料
https://leetcode.cn/problems/4sum/