ETH官方钱包

前往
大廳
主題

LeetCode - 436. Find Right Interval 解題心得

Not In My Back Yard | 2023-02-15 12:00:01 | 巴幣 0 | 人氣 179

題目連結:


題目意譯:
你被給定一個區間陣列 intervals,其中 intervals[i] = [starti, endi] 而每個 starti 皆彼此相異。

對於區間 i 來說,「右側區間」為一個區間 j 使得 startj ≧ endi 而 startj 盡可能地小。注意到,i 可能等於 j。

回傳一個由每個區間 i 所形成的右側區間之陣列。如果對於區間 i 來說不存在對應的右側區間,則於索引值 i 的位置放上 -1。

限制:
1 ≦ intervals.length ≦ 2 × 10 ^ 4
intervals[i].length == 2
-10 ^ 6 ≦ starti ≦ endi ≦ 10 ^ 6
每個區間的開頭彼此相異。



範例測資:
範例 1:
輸入: intervals = [[1,2]]
輸出: [-1]
解釋: 在集合中只有一個區間,所以其輸出 -1。

範例 2:
輸入: intervals = [[3,4],[2,3],[1,2]]
輸出: [-1,0,1]
解釋: 對於 [3,4] 來說沒有右側區間。
對於 [2,3] 來說的右側區間為 [3,4],因為 start0 = 3 為最小的開頭滿足其值 ≧ end1 = 3。
對於 [1,2] 來說的右側區間為 [2,3],因為 start1 = 2 為最小的開頭滿足其值 ≧ end2 = 2。

範例 3:
輸入: intervals = [[1,4],[2,3],[3,4]]
輸出: [-1,2,-1]
解釋: 對於 [1,4] 和 [3,4] 來說沒有右側區間。
對於 [2,3] 來說的右側區間為 [3,4],因為 start2 = 3 為最小的開頭滿足其值 ≧ end1 = 3。


解題思維:
本題有點類似這題,可以使用掃描線演算法(Sweep Line Algorithm)來解決。所以我們也需要將每個區間拆分成兩個獨立事件,並將這些事件附上「種類」和原本區間的「索引值」(用處可以參見這題,簡單來說就是排序事件用和求得答案用)。

因此現在每個事件為一個三元組 (i, j, k),其中 i 代表區間端點的位置(但光靠這個資訊不知是左側還是右側的)、j 代表其為左側或右側(等下再說明依序的值為何)、k 為原先區間的索引值。

將這些三元組按照字典序排序後,我們便倒著掃過這些三元組(也就是從最靠右的區間端點開始),並用一個變數 last 來代表最近被「完成」的區間(last 一開始為 -1,代表沒有區間被「完成」)。例如 [4, 6] 這個區間,我們在 6 這個位置的時候該區間還沒有被完成(還未結束),直到 4 這個位置才完成。此時 last 就可以設為該區間的索引值,來代表接下來的區間的右側區間為 last。

因此當我們倒著掃過所有端點時:
當遇到「左側」的端點的時候,我們就將該區間完成,因此將 last 設為該事件 k 值;
當遇到「右側」的端點的時候,我們就將其右側區間設為 last,即 answers[k] = last。
其中 answers[k] 存的是索引值 k 這個區間的右側區間之索引值。



不過,關鍵的 j 值還沒有定義。

此時我們回到原本的題目可以看到:一個區間的右側區間可以是自己本身。也就是說,對於 [5, 5] 這種左側等於右側的區間,該區間的右側區間就是自己。

因此這個時候我們可以觀察得到代表「左側」的 j 值應為 1、「右側」則為 0。因為如此一來按字典序排序後再倒著掃,此時對於 i 值一樣的區間我們會先看到其左側並將其「完成」,然後才碰到其右側而得到該區間的右側區間即為自己之結論。




此次分享到此為止,如有任何更加簡潔的想法或是有說明不清楚之地方,也煩請各位大大撥冗討論。

創作回應

更多創作