1. 程式人生 > >【LeetCode】23. Merge k Sorted Lists 解題報告(Python)

【LeetCode】23. Merge k Sorted Lists 解題報告(Python)

題目描述:

Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

Example:

Input:
[
  1->4->5,
  1->3->4,
  2->6
]
Output: 1->1->2->3->4->4->5->6

題目大意

把一個連結串列裡的k個有序連結串列合併成一個有序連結串列。

解題方法

方法一:每次遍歷最小值(TLE)

這個題是21. Merge Two Sorted Lists

的拓展,屬於經典題目,很容易想到的方法就是每次在lists中查詢最小的值,然後拼接到現在的連結串列尾部。需要注意的是,我們不能通過修改連結串列指標的方法來更新lists裡的頭部元素,所以只能強行賦值更新lists。

時間卡在了每次查詢連結串列最小元素這一步,導致超時。

時間複雜度是O(N*K),空間複雜度是O(1)。N是結果連結串列的長度,K是每次題目給出的連結串列個數。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution: def mergeKLists(self, lists): """ :type lists: List[ListNode] :rtype: ListNode """ head = ListNode(-1) move = head while True: curHead = ListNode(float('inf')) curIndex = -1 for i, llist in
enumerate(lists): if llist and llist.val < curHead.val: curHead = llist curIndex = i if curHead.val == float('inf'): break curNext = curHead.next move.next = curHead curHead.next = None move = curHead curHead = curNext lists[curIndex] = curHead return head.next

方法二:小根堆儲存值和索引

這個方法是根據上面超時的情況自然想出來的,我們每次需要用的是K個連結串列頭結點的最小值,所以把每個連結串列的頭結點都放在一個小根堆裡面。這樣,每次彈出來的就是最小連結串列的值,然後根據這個值的索引去Lists中找到對應節點,拼接到末尾就行。

有人使用的彈出堆裡面最小的值,然後重新生成新的節點的方式,這樣不好。

另外,程式碼裡需要注意的一個問題是,和方法一一樣,需要更新連結串列的頭結點才行,不能直接通過修改指標的方式修改,必須直接賦值更新。如果這個步驟少了的話,按照索引查詢就一直獲取的是老節點。

時間複雜度是O(N),空間複雜度是O(1)。N是結果連結串列的長度,K是每次題目給出的連結串列個數。

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        head = ListNode(-1)
        move = head
        heap = []
        heapq.heapify(heap)
        [heapq.heappush(heap, (l.val, i)) for i, l in enumerate(lists) if l]
        while heap:
            curVal, curIndex = heapq.heappop(heap)
            curHead = lists[curIndex]
            curNext = curHead.next
            move.next = curHead
            curHead.next = None
            move = curHead
            curHead = curNext
            if curHead:
                lists[curIndex] = curHead
                heapq.heappush(heap, (curHead.val, curIndex))
        return head.next

方法三:小根堆儲存值和節點

對於Python3,不能直接在堆裡面儲存節點,因為會造成無法比較的問題。但是對於python2就可以這麼做了,所以可以直接把節點的值和節點直接儲存到堆裡面,這樣每次彈出來的是最小的值的節點,直接使用就好了。

# Definition for singly-linked list.
# class ListNode(object):
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution(object):
    def mergeKLists(self, lists):
        """
        :type lists: List[ListNode]
        :rtype: ListNode
        """
        head = ListNode(-1)
        move = head
        heap = []
        heapq.heapify(heap)
        [heapq.heappush(heap, (l.val, l)) for i, l in enumerate(lists) if l]
        while heap:
            curVal, curHead = heapq.heappop(heap)
            curNext = curHead.next
            move.next = curHead
            curHead.next = None
            move = curHead
            curHead = curNext
            if curHead:
                heapq.heappush(heap, (curHead.val, curHead))
        return head.next

時間複雜度是O(N),空間複雜度是O(1)。N是結果連結串列的長度,K是每次題目給出的連結串列個數。

參考資料:

日期

2018 年 10 月 16 日 —— 下雨天還是挺舒服的