LintCode 104. 合并k个排序链表

题目描述

合并k个排序链表,并且返回合并后的排序链表。尝试分析和描述其复杂度。


输入参数

class Solution:

    """

    @param lists: a list of ListNode

    @return: The head of one sorted list.

    """

    def mergeKLists(self, lists):


测试样例

样例 1:

输入:  [2->4->null,null,-1->null]

输出:  -1->2->4->null

样例 2:

输入: [2->6->null,5->null,7->null]

输出:  2->5->6->7->null


解题思路

首先说明下,输入参数lists中是每个链表的头部,它们都是一个ListNode()对象。

1、堆

利用堆实现起来很方便,思路也很直接明了。

先设置一个dummy作为一个空节点,dummy.next将会是最终返回序列的head。同时,设置一个tail节点,初始化为dummy,用于在排序过程中将所有node链接起来。

将lists中的每个head都拿出来加入堆中(注意要判断下这个head是否为null),这样它们就会按照值由大到小进行排序。

接着,依次弹出堆中的node,直至所有node都被弹出。每弹出一个node,就将tail.next链到这个node,然后将这个node赋给tail。若当前node.next不为null,那么将node.next加入堆中。这个过程会令tail一直保持为堆中值最小的node。

最后返回dummy.next即为整个序列中值最小的head。

注意了,ListNode类型本身并没有定义比较大小的方法,因此不能直接加入堆,这里有两种方法:

i). 自定义 ListNode.__lt__ == lambda node1, node2: node1 < node2;

ii). 将(node.val, index, node)三元组加入堆中,之所以要加上index是因为可能存在值相同的node

2、自顶向下的分冶归并

这种方法的思想是将当前待排序的范围分冶成一个个已排序好的小范围,获得已排序好的各个小范围后,再将它们相互进行排序归并。

3、自底向上的两两归并

与第2种方法的归并顺序相反,该方法的思想是不断对序列中的元素进行两两归并,直至序列归并为一个元素。


代码

1、堆

自定义__lt__的方式:

"""

Definition of ListNode

class ListNode(object):

    def __init__(self, val, next=None):

        self.val = val

        self.next = next

"""

# 重载less than用于比较ListNode的值大小

ListNode.__lt__ = lambda node1, node2: node1.val < node2.val

import heapq

class Solution:

    """

    @param lists: a list of ListNode

    @return: The head of one sorted list.

    """

    def mergeKLists(self, lists):

        # write your code here

        heap = []

        for node in lists:

            # 注意要判断下node是否为null

            if node:

                heapq.heappush(heap, node)


        dummy = ListNode(None)

        tail = dummy


        while heap:

            # tail每次都变为heap中值最小的node

            head = heapq.heappop(heap)

            tail.next = head

            tail = tail.next


            if head.next:

                heapq.heappush(heap, head.next)


        return dummy.next

将元组加入堆的方式:

i).

import heapq

class Solution:

    """

    @param lists: a list of ListNode

    @return: The head of one sorted list.

    """

    def mergeKLists(self, lists):

        # write your code here

        heap = []

        for index, node in enumerate(lists):

            # 注意要判断下node是否为null

            if node:

                # 将node.val加入heap用于排序

                # 因为本身ListNode没有定义比较大小的方法

                # 并且由于因为有值相同的node,因此还要加入索引用于排序比较

                heapq.heappush(heap, (node.val, index, node))


        dummy = ListNode(None)

        tail = dummy


        while heap:

            # tail每次都变为heap中值最小的node

            _, index, head = heapq.heappop(heap)

            tail.next = head

            tail = tail.next


            if head.next:

                heapq.heappush(heap, (head.next.val, index, head.next))


        return dummy.next

ii).

import heapq

class Solution:

    """

    @param lists: a list of ListNode

    @return: The head of one sorted list.

    """

    def mergeKLists(self, lists):

        # write your code here

        heap = []

        for node in lists:

            # 注意要判断下node是否为null

            while node:

                heapq.heappush(heap, node.val)

                node = node.next


        dummy = ListNode(None)

        tail = dummy


        while heap:

            # heap弹出的是节点的值,需要重新构造ListNode

            head = ListNode(heapq.heappop(heap))

            tail.next = head

            tail = tail.next


        return dummy.next

2、自顶向下的分冶归并

class Solution:

    """

    @param lists: a list of ListNode

    @return: The head of one sorted list.

    """

    def mergeKLists(self, lists):

        return self.merge_range_lists(lists, 0, len(lists) - 1)


    def merge_range_lists(self, lists, start, end):

        if start == end:

            return lists[start]


        # 分冶

        mid = (start + end) // 2

        left = self.merge_range_lists(lists, start, mid)

        right = self.merge_range_lists(lists, mid + 1, end)


        return self.merge_two_lists(left, right)


    def merge_two_lists(self, head1, head2):

        tail = dummy = ListNode(None)


        # tail始终为head1和head2的较小者

        while head1 and head2:

            if head1.val < head2.val:

                tail.next = head1

                head1 = head1.next

            else:

                tail.next = head2

                head2 = head2.next


            tail= tail.next


        # 注意head1或head2可能还存在

        if head1:

            tail.next = head1

        if head2:

            tail.next = head2


        return dummy.next

3、自底向上的两两归并

class Solution:

    """

    @param lists: a list of ListNode

    @return: The head of one sorted list.

    """

    def mergeKLists(self, lists):

        # 自底向上将lists中的head两两归并

        # 直至lists中归并为一个head

        while len(lists) > 1:

            merged_lists = []


            for i in range(0, len(lists), 2):

                if i + 1 < len(lists):

                    merged_head = self.merge_two_lists(lists[i], lists[i +1])

                else:

                    merged_head = lists[i]


                merged_lists.append(merged_head)


            lists = merged_lists


        return lists.pop()


    def merge_two_lists(self, head1, head2):

        tail = dummy = ListNode(None)


        # tail始终为head1和head2的较小者

        while head1 and head2:

            if head1.val < head2.val:

                tail.next = head1

                head1 = head1.next

            else:

                tail.next = head2

                head2 = head2.next


            tail= tail.next


        # 注意head1或head2可能还存在

        if head1:

            tail.next = head1

        if head2:

            tail.next = head2


        return dummy.next

你可能感兴趣的:(LintCode 104. 合并k个排序链表)