今天是紀錄LeetCode解題的第二十三天
又來看一題困難題
第二十三題題目:You are given an array of k linked-lists lists, each linked-list is sorted in ascending order.
Merge all the linked-lists into one sorted linked-list and return it.
給定k個鏈結串列,每個鏈結串列按升序排列,將所有鏈結串列合併成一個並回傳
分治法(Divide and Conquer)
最小堆(Min-Heap/Priority Queue)
class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        if not lists:
            return None
        return self.mergeRange(lists,0,len(lists)-1)
    def mergeRange(self,lists,left,right):
        if left == right:
            return lists[left]
        mid = (left + right) // 2
        l1 = self.mergeRange(lists,left,mid)
        l2 = self.mergeRange(lists,mid + 1,right)
        return self.mergeTwoList(l1,l2)
    def mergeTwoList(self,l1,l2):
        dummy = ListNode(0)
        tail = dummy
        while l1 and l2:
            if l1.val < l2.val:
                tail.next = l1
                l1 = l1.next
            else:
                tail.next = l2
                l2 = l2.next
            tail = tail.next
        tail.next = l1 if l1 else l2
        return dummy.next
初始狀態
分治過程

合併過程
import heapq
class Solution:
    def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]:
        heap = []
        dummy = ListNode(0)
        tail = dummy
        for i,node in enumerate(lists): #加上i來避免node.val相同時無法比較node物件
            if node:
                heapq.heappush(heap,(node.val,i,node)) #初始先把鏈結串列的最小值都加入到heap中
        while heap:
            val,idx,node = heapq.heappop(heap) #取出最小的值
            tail.next = node
            tail = tail.next
            if node.next:
                heapq.heappush(heap, (node.next.val, idx, node.next)) #把剛加入的最小值的下一個節點加入到heap裡
        return dummy.next
heapq是Python內建的模組,可以把list當作最小堆操作
| 函式 | 說明 | 
|---|---|
| heapq.heappush(heap, item) | 把一個元素放進最小堆中 | 
| heapq.heappop(heap) | 取出並移除堆中「最小」的元素 | 
| heapq.heapify(lst) | 把 list 轉成最小堆 | 
初始狀態
第一次執行
第二次執行
第三次執行
第四次執行
第五次執行

依此類推直到heap為空為止就合併排序好所有鏈結串列了
分治法
不斷將鏈結串列拆分,分為左半邊left ~ mid及右半邊mid + 1 ~ right,再將拆分的範圍傳入函式繼續拆分,直到拆分到只剩下一個鏈結串列,也就是left = right時,回傳鏈結串列,接著做合併
最小堆
先取出每個鏈結串列中最小的節點並放進heap裡,再從heap中取出最小的節點放到結果鏈結串列中,接著把該最小節點的下一個節點放進heap,循環往復直到heap為空(小細節:取出的節點值要記錄索引值,避免節點的值相同的情況下無法比較node物件大小)