1. 程式人生 > 其它 >【每日演算法/刷穿 LeetCode】23. 合併K個升序連結串列(困難)

【每日演算法/刷穿 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題解
#演算法面試

宮水三葉的刷題日記