這是「合併k個已排序鏈結串列」問題。
這個問題要求將一個包含k個已排序鏈結串列(Linked Lists)的陣列lists合併成一個單一的、完整排序的鏈結串列,並回傳這個新的鏈結串列的頭部(Head)。
這題需要找到所有節點中的最小值,將其作為新串列的第一個節點,然後從該串列中移除該節點。重複這個過程,直到所有的串列都為空。
由於所有鏈結串列都已排序,需要一種高效的方式來同時追蹤k個串列的目前節點,並在每一輪中快速找到k個節點中的最小值,而這個方法就是優先佇列(Priority Queue),在java中即為java.util.PriorityQueue。這個方法能確保我們在k個串列頭部節點中,已O(log k)的時間複雜度找到最小值。
首先,要定義鏈結串列節點(ListNode),但這次LeetCode已經提供,所以略過。
接著,建立一個最小堆(Min-Heap)結構的優先佇列,用來儲存k個鏈結串列的頭部節點。佇列中的節點會根據它們的 val(值)進行排序。
再來,遍歷輸入lists陣列,將所有非空的鏈結串列的頭部節點加入優先佇列。
上述完成後,建立一個虛擬頭部(Dummy Head)節點dummy,並使用一個指標tail來追蹤新串列的尾部,以便於附加新節點。
只要優先佇列不為空,就重複以下動作:
1.取出最小值:從佇列中取出(poll)值最小的節點smallest。
2.附加到結果串列:將smallest節點附加到結果串列的尾部(即tail.next = smallest),並移動tail指標到新的尾部。
3.加入下一個節點:檢查smallest節點是否有下一個節點(smallest.next != null)。如果有,將這個下一個節點加入優先佇列。
最終回傳dummy.next,它就是合併後鏈結串列的頭部。
複雜度分析
時間複雜度: O(N log k)
1.N 是所有鏈結串列中的節點總數(即 ∑lists[i].length)。
2.佇列中最多會有 k 個元素。
3.每個節點都會被加入和取出佇列一次。
4.每次加入或取出操作的時間複雜度是 O(logk)。
5.因此總時間複雜度為 N×O(logk)=O(Nlogk)。
空間複雜度: O(k)
1.優先佇列最多會同時儲存 k 個節點(每個串列一個頭部)。
這個 O(N log k) 的解法是最高效的,因為它平衡了「遍歷所有節點」 (O(N)) 和「在 k 個選項中找最小值」 (O(log k)) 這兩個核心操作。