LeetCode-23-合并K个排序链表


题意描述:

合并 k 个排序链表,返回合并后的排序链表。请分析和描述算法的复杂度。


示例:

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

解题思路:

Alice: 我想起来你以前反转链表的做法了。
Bob: 你是说先把所有节点的值都存起来,然后排序,然后再重新塞到 原来的链表里面。
Alice: 对啊,不过这里面没有现成的链表可以填充啊 ?
Bob: 那就把那 k 个链表首尾相连呗,反正节点的数量对得上,最后返回头结点就是了。
Alice: emm, 这样的时间复杂度应该是O(n * log n) + O(n) , 然后空间复杂度应该是 O(n),空间复杂度有点高诶。
Bob: 那就直接合并 k 个有序链表吧, 每次从所有的链表头 找到值最小的那一个,接上去,然后一直接下去就好了。
Alice: 时间复杂度呢 ?
Bob: 时间复杂度应该是O(k N) k 是链表个数,N 是节点个数。不过空间复杂度倒是很小, O(1)
Alice: 你说这两个方法哪个更快呀 ?
Bob: 当然是 O(n log n) 啊,一般而言,空间复杂度越高,时间复杂度就会稍微低一些。空间换时间嘛。
Alice: 😎😎


代码:

Python 方法一: 使用库函数和辅助数组排序,时间复杂度O(n * log n),空间复杂度 O(n)。

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

class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:
        
        data = []
        headAndTails = []

        for head in lists:
            if head == None:
                # 有空链表直接跳过
                continue
            headAndTails.append(head)
            node = head
            while node.next != None:
                data.extend([node.val])
                node = node.next
            data.extend([node.val])
            headAndTails.append(node)
        
        for x in range(1, len(headAndTails)-1, 2):
            # 将lists中的链表首尾相连
            headAndTails[x].next = headAndTails[x+1]
        
        if len(headAndTails) == 0:
            return None
        
        data.sort()
        # 排序
        node = headAndTails[0]
        for x in data:
            # 将排序后的结果填充回链表
            node.val = x
            node = node.next

        return headAndTails[0]

            

Java 方法一: ArrayList 排序外部数组,时间复杂度O(n*log n) 空间复杂度 O(n)。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {

        ListNode node = new ListNode(0);
        int tot = 0;
        List<ListNode> headAndTails = new ArrayList<ListNode>();
        List<Integer> data = new ArrayList<Integer>();

        for(int i=0; i<lists.length; ++i){
            if(lists[i] == null){          // 跳过空链表
                continue;
            }
            node = lists[i];
            headAndTails.add(node);
            while(node.next != null){
                data.add(node.val);
                node = node.next;
            }
            data.add(node.val);
            headAndTails.add(node);
        }

        if(headAndTails.size() == 0){       // lists 中的链表全是空链表
            return null;
        }

        for(int i=1; i<headAndTails.size()-1; i+=2){        // 将lists中的链表尾首相连
            headAndTails.get(i).next = headAndTails.get(i+1);
        }

        Collections.sort(data);                              // 排序外部数组

        node = headAndTails.get(0);                          // 将排序后的结果填充进链表
        for(int i=0; i<data.size(); ++i){
            node.val = data.get(i);
            node = node.next;
        }       

        return headAndTails.get(0);
    }
}

Python 方法二: 直接合并 =》超时。

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

class Solution:
    def mergeKLists(self, lists: List[ListNode]) -> ListNode:

        head = ListNode(0);
        tot = 0

        # 统计节点总数
        for node in lists:
            while node != None:
                tot += 1
                node = node.next
        
        # 合并所有链表节点
        cnt = 0
        node = head
        while cnt < tot:
            node.next = self.getNextNode(lists)
            node = node.next
            cnt += 1

        return head.next

    def getNextNode(self, lists):

        minValue = 2 ** 31 - 1
        minNode  = None

        for node in lists:
            if node != None and node.val < minValue:
                minValue = node.val
                minNode  = node
        
        for x in range(len(lists)):
            if lists[x] != None and lists[x] == minNode:
                lists[x] = lists[x].next
                break

        return minNode

Java 方法二: 直接合并,时间复杂度O(n^2),空间复杂度O(1)。

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeKLists(ListNode[] lists) {
        
        int tot = 0;
        ListNode head = new ListNode(0);
        ListNode node = new ListNode(0);

        // 统计节点总个数
        for(int i=0; i<lists.length; ++i){
            node = lists[i];
            while(node != null){
                tot += 1;
                node = node.next;
            }
        }
        //System.out.println(lists.length);

        node = head;
        int cnt = 0;
        while(cnt < tot){
            node.next = get(lists);
            node = node.next;
            cnt += 1;
        }
        return head.next;
    }
    public ListNode get(ListNode[] lists){

        int minValue = Integer.MAX_VALUE;
        ListNode retNode  = null;
        for(int i=0; i<lists.length; ++i){
            if(lists[i] != null && lists[i].val < minValue){
                minValue = lists[i].val;
                retNode  = lists[i];
            }
        }
        for(int i=0; i<lists.length; ++i){
            if(lists[i] != null && lists[i] == retNode){
                lists[i] = lists[i].next;
                break;
            }
        }
        return retNode;
    }
}

易错点:

  • 一些测试样例:
[[1,4,5],[1,3,4],[2,6]]
[[1,4,5],[],[2,6]]
[[],[],[2,6]]
[[],[]]
[[1],[2]]
  • 答案:
[1,1,2,3,4,4,5,6]
[1,2,4,5,6]
[2,6]
[]
[1,2]

总结:

在这里插入图片描述


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值