合并k个有序链表

题目:

合并k个有序链表,并将结果用一个有序链表输出

例如:
输入: [   1->4->5,   1->3->4,   2->6 ] 输出: 1->1->2->3->4->4->5->6

思路:

假设k个链表的总元素数目为n。首先想到两两合并列表,在序列1和2合并,3和4合并,依次类推。直到合并的只剩一个链表。这种操作的时间复杂度为O(nlog(k)),空间复杂度为O(1)。python代码如下:

class Solution(object):
    def mergeKLists(self, lists):
        if not lists:
            return None
        while len(lists) > 1:
            tmp_node = self.mergeTwoLists(lists.pop(0), lists.pop(0))
            lists.append(tmp_node)
        return lists[0]

    def mergeTwoLists(self, p1, p2):
        new_head = ListNode(-1)
        tail = new_head
        while p1 is not None and p2 is not None:
            if p1.val <= p2.val:
                tail.next, tail = p1, p1
                p1 = p1.next
            else:
                tail.next, tail = p2, p2
                p2 = p2.next
        if p1 is None:
            tail.next = p2
        elif p2 is None:
            tail.next = p1
        return new_head.next

注意到在mergeTwoLists()中使用了循环进行合并。当节点数量n大于1000时,使用循环合并比较有效。因为python默认限制函数迭代次数为1000,用迭代的方法合并两个链表,节点数多了就会报错。

还可以同时合并所有列表,这中间需要比较这k个链表的头结点哪个最小。直接比较效率低,想到构建辅助数组,用最大堆来帮助比较。这样做的时间复杂度也是O(nlog(k)),空间复杂度为O(k)。同时注意到某些链表合并完后,辅助数组的长度减小,单次查找速度复杂度会小于log(k)。因此这种用最小堆合并的方式速度会比二分合并快一些。实际上在LeetCode23. Merge k Sorted Lists的测试用例上跑的时候,两种方法花的时间分别是165ms,103ms。

import heapq
class Solution(object):
    def mergeKLists(self, lists):
        head = ListNode(-1)
        current = head
        heap = []
        for node in lists:
            if node:
                heap.append((node.val, node))
        heapq.heapify(heap)
        while heap:
            _, ref = heapq.heappop(heap)
            current.next = ref
            current = current.next
            if ref.next:
                heapq.heappush(heap, (ref.next.val, ref.next))
        return head.next

 

posted @ 2018-06-06 11:38  板弓子  阅读(1454)  评论(0编辑  收藏  举报