【每日演算法/刷穿 LeetCode】23. 合併K個升序連結串列(困難)
技術標籤:LeetCode 題解演算法與資料結構刷穿 LeetCode連結串列演算法資料結構javaleetcode
點選 這裡 可以檢視更多演算法面試相關內容~
題目描述
給你一個連結串列陣列,每個連結串列都已經按升序排列。
請你將所有連結串列合併到一個升序連結串列中,返回合併後的連結串列。
示例 1:
輸入:lists = [[1,4,5],[1,3,4],[2,6]] 輸出:[1,1,2,3,4,4,5,6] 解釋:連結串列陣列如下: [ 1->4->5, 1->3->4, 2->6 ] 將它們合併到一個有序連結串列中得到。 1->1->2->3->4->4->5->6
示例 2:
輸入:lists = []
輸出:[]
示例 3:
輸入:lists = [[]]
輸出:[]
提示:
k == lists.length
0 <= k <= 10^4
0 <= lists[i].length <= 500
-10^4 <= lists[i][j] <= 10^4
lists[i]
按升序排列lists[i].length
的總和不超過 10^4
優先佇列解法(哨兵技巧)
哨兵技巧我們在前面的多道連結串列題講過,讓三葉來幫你回憶一下:
做有關連結串列的題目,有個常用技巧:新增一個虛擬頭結點(哨兵),幫助簡化邊界情況的判斷。
由於所有連結串列本身滿足「升序」,一個直觀的做法是,我們比較每條連結串列的頭結點,選取值最小的節點,新增到結果中,然後更新該連結串列的的頭結點為該節點的 next 指標。迴圈比較,直到所有的節點都被加入結果中。
對應到程式碼的話,相當於我們需要準備一個「集合」,將所有連結串列的頭結點放入「集合」,然後每次都從「集合」中挑出最小值,並將最小值的下一個節點新增進「集合」(如果有的話),迴圈這個過程,直到「集合」為空(說明所有節點都處理完,進過集合又從集合中出來)。
而「堆」則是滿足這樣要求的資料結構:
class Solution {
public ListNode mergeKLists(ListNode[] lists) {
ListNode dummy = new ListNode(-1), tail = dummy;
PriorityQueue<ListNode> q = new PriorityQueue<>((a, b) -> a.val - b.val);
for (ListNode node : lists) {
if (node != null) q.add(node);
}
while (!q.isEmpty()) {
ListNode poll = q.poll();
tail.next = poll;
tail = tail.next;
if (poll.next != null) q.add(poll.next);
}
return dummy.next;
}
}
-
時間複雜度:會將每個節點處理一遍。複雜度為 O(n)
-
空間複雜度:O(1)
最後
這是我們「刷穿 LeetCode」系列文章的第 No.23
篇,系列開始於 2021/01/01,截止於起始日 LeetCode 上共有 1916 道題目,部分是有鎖題,我們將先將所有不帶鎖的題目刷完。
在這個系列文章裡面,除了講解解題思路以外,還會盡可能給出最為簡潔的程式碼。如果涉及通解還會相應的程式碼模板。
由於 LeetCode 的題目隨著周賽 & 雙週賽不斷增加,為了方便我們統計進度,我們將按照系列起始時的總題數作為分母,完成的題目作為分子,進行進度計算。當前進度為 23/1916
。
為了方便各位同學能夠電腦上進行除錯和提交程式碼,我建立了相關的倉庫:Github 地址 & Gitee 地址。
在倉庫地址裡,你可以看到系列文章的題解連結、系列文章的相應程式碼、LeetCode 原題連結和一些其他的優選題解。
#演算法與資料結構
#LeetCode題解
#演算法面試