1. 程式人生 > 實用技巧 >LeetCode 23. 合併K個升序連結串列

LeetCode 23. 合併K個升序連結串列

好久沒刷題了,這個困難的題目,果然還是需要對連結串列的特性有一定的熟悉才好入手。
也是卡了好久,記錄一下題解大大的做法,後面會再二刷、三刷,一定要摸清這些題目的規律

題目


給你一個連結串列陣列,每個連結串列都已經按升序排列。

請你將所有連結串列合併到一個升序連結串列中,返回合併後的連結串列。

示例 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

思路

方法一:

hmm,不用過腦子的話,先想到的是將每個連結串列內容都塞入陣列,排序後再轉連結串列返回。

class Solution(object):
    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        listArray = []
        for singleNode in lists:
            while singleNode:
                listArray.append(singleNode.val)
                singleNode = singleNode.next
        resNode = temNode = ListNode(0)
        listArray.sort(reverse=False) #sort 排序,false 從小到大
        for temp in listArray:
            temNode.next = ListNode(temp)
            temNode = temNode.next
        return resNode.next

執行用時:80 ms, 在所有 Python 提交中擊敗了86.79%的使用者

記憶體消耗:21.6 MB, 在所有 Python 提交中擊敗了23.45%的使用者

還有一個同樣的思路是轉dic,用key、value的形式去存連結串列,通過dic.keys 返回list再用sort排序,最後再轉化整個連結串列。

方法二:

分治,摘自題解大大的一個圖片。

分治的思想就是各自以中間點為分割比較,直至一方不存在,再合併到另一個連結串列。

class Solution(object):
    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        length = len(lists)

        # 邊界情況
        if length == 0:
            return None
        if length == 1:
            return lists[0]
        # 分治
        mid = length / 2
        return self.merge(self.mergeKLists(lists[:mid]), self.mergeKLists(lists[mid:length]))
    def merge(self, node_a, node_b):
        dummy = ListNode(None)
        cursor_a, cursor_b, cursor_res = node_a, node_b, dummy
        while cursor_a and cursor_b:  # 對兩個節點的 val 進行判斷,直到一方的 next 為空
            if cursor_a.val <= cursor_b.val:
                cursor_res.next = ListNode(cursor_a.val)
                cursor_a = cursor_a.next
            else:
                cursor_res.next = ListNode(cursor_b.val)
                cursor_b = cursor_b.next
            cursor_res = cursor_res.next
        # 有一方的next的為空,就沒有比較的必要了,直接把不空的一邊加入到結果的 next 上
        if cursor_a:
            cursor_res.next = cursor_a
        if cursor_b:
            cursor_res.next = cursor_b
        return dummy.next

方法三:

還有一個類似方法一的做法,就是通過python的一個庫-->heapq來實現push和pop操作,其中彈出的元素為堆中最小的element

heappush(heap, item) # pushes a new item on the heap

item = heappop(heap) # pops the smallest item from the heap

class Solution(object):
    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        if not lists or len(lists) == 0:
            return None
        import heapq
        heap = []
        # 首先 for 巢狀 while 就是將所有元素都取出放入堆中
        for node in lists:
            while node:
                heapq.heappush(heap, node.val)
                node = node.next
        dummy = ListNode(None)
        cur = dummy
        # 依次將堆中的元素取出(因為是小頂堆,所以每次出來的都是目前堆中值最小的元素),然後重新構建一個列表返回
        while heap:
            temp_node = ListNode(heappop(heap))
            cur.next = temp_node
            cur = temp_node
            print(heap)
        return dummy.next