前往
大廳
主題

LeetCode - 2092. Find All People With Secret 解題心得

Not In My Back Yard | 2024-05-12 12:00:05 | 巴幣 0 | 人氣 29

題目連結:


題目意譯:
你被給定一個整數 n 代表著現在有 n 個人且編號為 0 到 n - 1。你同時也被給定一個索引值從 0 開始數的二維整數陣列 meetings,其中 meetings[i] = [xi, yi, timei] 代表著編號 xi 和編號 yi 的人在時間點 timei 時有會議。而同一個人可能會同時參加多個會議。最終,你還會被給定一個整數 firstPerson。

編號 0 的人有一個祕密,而他在一開始時間 0 的時候告訴祕密給編號 firstPerson 的人。而這個祕密將會在每次知道祕密的人參加會議時分享給其他人。更正式地說,對於每場會議,如果編號 xi 的人在時間點 timei 前知道祕密,則他會在會議中分享祕密給編號 yi 的人;反之亦然。

祕密的分享是立即性的。也就是說,某個人可以在知曉祕密的同一瞬間將該祕密分享給他同時參加的其他會議上的人。

回傳一個由在所有會議結束之後,知道祕密的所有人所組成的列表。你可以按任意順序回傳答案。

限制:
2 ≦ n ≦ 10 ^ 5
1 ≦ meetings.length ≦ 10 ^ 5
meetings[i].length == 3
0 ≦ xi, yi ≦ n - 1
xi != yi
1 ≦ timei ≦ 10 ^ 5
1 ≦ firstPerson ≦ n - 1



範例測資:
範例 1:
輸入: n = 6, meetings = [[1,2,5],[2,3,8],[1,5,10]], firstPerson = 1
輸出: [0,1,2,3,5]
解釋:
在時間點 0,編號 0 的人與編號 1 的人分享祕密。
在時間點 5,編號 1 的人與編號 2 的人分享祕密。
在時間點 8,編號 2 的人與編號 3 的人分享祕密。
在時間點 10,編號 1 的人與編號 5 的人分享祕密。
因此,編號 0 、 1 、 2 、 3 和 5 的人在所有會議結束後是知道祕密的。

範例 2:
輸入: n = 4, meetings = [[3,1,3],[1,2,2],[0,3,3]], firstPerson = 3
輸出: [0,1,3]
解釋:
在時間點 0,編號 0 的人與編號 3 的人分享祕密。
在時間點 2,編號 1 和 2 的兩個人都不知道祕密。
在時間點 3,編號 3 的人與編號 0 和 1 的人分享祕密。
因此,編號 0 、 1 和 3 的人在所有會議結束後是知道祕密的。

範例 3:
輸入: n = 5, meetings = [[3,4,2],[1,2,1],[2,3,1]], firstPerson = 1
輸出: [0,1,2,3,4]
解釋:
在時間點 0,編號 0 的人與編號 1 的人分享祕密。
在時間點 1,編號 1 的人與編號 2 的人分享祕密,而編號 2 的人再分享祕密給編號 3 的人。
注意到編號 2 的人可以在知道祕密的同時分享給其他人。
在時間點 2,編號 3 的人與編號 4 的人分享祕密。
因此,編號 0 、 1 、 2 、 3 和 4 的人在所有會議結束後是知道祕密的。


解題思維:
首先我們把所有會議按照開始的時間點由小排到大,並將相同時間點的會議放在一起看(可以全部丟到一個陣列中等。注意,這邊是把會議聚在一起,不是人本身聚在一起。)



假設現在時間點是 T,而且有 m1 、 m2 、 …… 、 mk 這些會議要進行,其中 mi = [xi, yi] 代表著 xi 和 yi 在這個時間點 T 有會議。

為了「即時」分享祕密,我們需要知道哪些人是一組的。因此我們需要掃過每一個會議 mi,來把 xi 、 yi 分在同一組(先不論實際上要怎麼實作)。

例如說我們可能有 [0, 1] 、 [1, 2] 和 [5, 6] 這三場會議。則掃完會議之後,我們應當要知道 [0, 1, 2] 是一組的,而 [5, 6] 是另一組。可以看到這就是為何前面提到不能直接把人聚在一起,因為會議時間點一樣不代表在這邊會是同一組。

而此時我們便可以讓同一組的人彼此分享祕密(如果有人知道的話)。再次提醒這組的祕密分享是與其他組獨立的。

因為這個分組只在這個時間點有意義而已,因此分享完之後就要各自分散了。由小到大判斷完所有時間點各自的會議之後,再掃過一次所有人看哪些人知道祕密。把他們丟進一個陣列中即是所求。



接著來談實作,可以看到「組」的概念即是「集合」。「分在同一組」可以看作是集合之間的「合併」。因此我們可以使用併查集(Union-Find Set,參見這題的介紹)來實作。注意在將兩個集合合併時,如果此時兩個集合中的「代表」(Representative)有某一個知道祕密則合併之後的集合之代表也需要「繼承」這個祕密,方便後面分享祕密的時候可以直接參考集合代表知不知道祕密。

分完組之後,再掃過這期間有參加過會議的人(其實就是再掃過一次 m1 、 m2 、 …… 、 mk)來判斷各自會不會被分享到祕密(如上所述,參見同一集合中的代表即可)。

分享完祕密後,需要再把組別各自拆開。也就是說,要將集合重設到原本各自獨立一個的狀態。一樣,這邊可以再掃過一次所有會議來看哪些人有參加會議。把他們的集合資訊重設即可。

其餘部份是一樣的。



最後是時間複雜度分析:
可以看到單一一個時間點 T 所需時間為 O(k × α(k))。而每個時間點之間的 k 值不一定一樣,但是全部的 k 值加總為 M,即為 meetings 的長度。因此併查集的部份總體是 O(M × α(M))。

而一開始對時間大小排序,因此時間為 O(M × log(M))。同時最後求得答案需要掃過所有人,因此時間為 O(n)。

因此總體時間複雜度為 O(M × log(M)) + O(M × α(M)) + O(n) = O(M × log(M) + n)。




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

創作回應

更多創作